Compare commits

...

166 Commits

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

* ACS-3431: Fixing assertions.

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

* ACS-3431: Small test refactorings.

* ACS-3431: Small test refactorings.

* ACS-3431: Adding more tests and refactorings.

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

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

* ACS-3429: Removing duplicated assertion.

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

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

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

* ACS-3435: Revert unnecessary change

* ACS-3435: added tests

* ACS-3435: move test assertions

* ACS-3435: adding tests

Co-authored-by: mpichura <maciej.pichura@hyland.com>
2022-08-24 15:58:04 +03:00
Travis CI User
f38a36910f [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-24 11:57:18 +00:00
Travis CI User
972f81ab8b [maven-release-plugin][skip ci] prepare release 17.92 2022-08-24 11:57:16 +00:00
Domenico Sibilio
1bd0dfd114 ACS-3351 Bump Alfresco JLAN to 7.2 (#1334) 2022-08-24 13:14:03 +02:00
Travis CI User
775de0e94c [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-21 00:10:37 +00:00
Travis CI User
78d2ed247a [maven-release-plugin][skip ci] prepare release 17.91 2022-08-21 00:10:35 +00:00
Alfresco CI User
5ca3630398 [force] Force release for 2022-08-21. 2022-08-21 00:03:38 +00:00
Travis CI User
ee7383dcab [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-19 15:10:22 +00:00
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
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
f8d66ec76d [maven-release-plugin][skip ci] prepare release 17.78 2022-08-09 09:59:42 +00:00
mstrankowski
94a47d0368 [skip tests] Trigger version update 2022-08-09 11:52:24 +02:00
Tom Page
8884cc9563 ACS_3362 GET rule set can include optional owningFolder field. (#1280)
* ACS_3362 GET rule set can include optional owningFolder field. [skip ci]

* ACS_3362 Update to use release version of TAS. [tas]

* ACS_3362 Refactor RuleSetLoader into its own class. [tas]
2022-08-09 10:05:14 +01:00
dependabot[bot]
594f02e7cd Bump junrar from 7.5.2 to 7.5.3 (#1281) 2022-08-09 09:04:42 +00:00
kavitshah-gl
cb29f1e9ec Feature/apps 1550 (#1212)
* 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]

* Revert "[ags api]"

This reverts commit 2153eafc0f.

* Fixed Review Comments [ags]

Co-authored-by: sbisht <shishuraj.bisht@globallogic.com>
2022-08-09 14:31:28 +05:30
Travis CI User
59816bd071 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-09 08:30:29 +00:00
Travis CI User
bb77023e1f [maven-release-plugin][skip ci] prepare release 17.77 2022-08-09 08:30:26 +00:00
mstrankowski
fa7cb58044 Retrigger master build due to nexus failure 2022-08-09 09:54:43 +02:00
Travis CI User
4962ce1111 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-08 15:24:19 +00:00
Travis CI User
20a0bb7194 [maven-release-plugin][skip ci] prepare release 17.76 2022-08-08 15:24:16 +00:00
dependabot[bot]
1e1bebd19c Bump alfresco-messaging-repo from 1.2.19 to 1.2.20 (#1196) 2022-08-08 14:41:57 +00:00
Travis CI User
03dedb4140 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-08 13:02:05 +00:00
Travis CI User
66f6174b87 [maven-release-plugin][skip ci] prepare release 17.75 2022-08-08 13:02:03 +00:00
mikolajbrzezinski
885f21ff86 ACS-3316 Fix HTML sanitisation bypass (#1266)
* ContentGet context file update

* Get mimetype from ContentReader and check if should be forced to downlaod

* Changes according to comments

* Code duplication removal

* Missing spaces, touch-ups to Javadoc and logic

* tests for slingshot

* Tests for contentGet and formatting changes
2022-08-08 14:26:33 +02:00
Tom Page
501d9204a9 ACS-3360 E2E tests for GET rule sets. [tas] (#1264)
* ACS-3360 GET APIs for rule sets.

Move RulesImpl and RuleSetsImpl into their own package.
Split out node validation into a new class.

* ACS-3360 E2E tests for GET rule sets. [tas]

* ACS-3360 GET APIs for rule sets E2E tests.

* ACS-3360 GET APIs for rule sets E2E tests.

* ACS-3360 GET APIs for rule sets E2E tests.

* ACS-3360 Update comment [skip ci][skip tests]

Co-authored-by: Krystian Dabrowski <krystian.dabrowski@hyland.com>
2022-08-08 11:29:03 +01:00
dependabot[bot]
924005e94e Bump jetty-webapp from 8.2.0.v20160908 to 9.4.34.v20201102 in /remote-api (#270)
* Bump jetty-webapp in /remote-api

Upping jetty to 10.0.11 with a few necessary modifications to avoid errors
Swapping charsets to lowercase, adding ignoring of ambiguous link security issues for jetty (since it is only used in 

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mstrankowski <marcin.strankowski@hyland.com>
2022-08-08 11:59:07 +02:00
Alfresco CI User
3a34c42d2f [force] Force release for 2022-08-07. 2022-08-07 00:03:34 +00:00
Travis CI User
332af85227 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-06 13:46:10 +00:00
Travis CI User
556c13eba0 [maven-release-plugin][skip ci] prepare release 17.74 2022-08-06 13:46:08 +00:00
dependabot[bot]
3caf6bf9f3 Bump alfresco-opencmis-extension from 2.0 to 2.1 (#1277) 2022-08-06 13:07:29 +00:00
Travis CI User
b5fcc5370a [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-06 10:13:41 +00:00
Travis CI User
29007871e8 [maven-release-plugin][skip ci] prepare release 17.73 2022-08-06 10:13:39 +00:00
dependabot[bot]
12df503cc2 Bump restapi from 1.100 to 1.101 (#1279) 2022-08-06 09:22:07 +00:00
Travis CI User
e3a9e9c034 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-06 08:34:50 +00:00
Travis CI User
d116cf397b [maven-release-plugin][skip ci] prepare release 17.72 2022-08-06 08:34:48 +00:00
dependabot[bot]
271c123a00 Bump alfresco-greenmail from 6.2 to 6.4 (#1278) 2022-08-06 08:01:11 +00:00
Travis CI User
5bae1ca9b6 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-06 01:35:04 +00:00
Travis CI User
f84c82c6a2 [maven-release-plugin][skip ci] prepare release 17.71 2022-08-06 01:35:02 +00:00
dependabot[bot]
c639eec1df Bump acs-event-model from 0.0.15 to 0.0.16 (#1274) 2022-08-06 01:03:07 +00:00
Travis CI User
d2e561dc95 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-06 00:37:30 +00:00
Travis CI User
54347fbbee [maven-release-plugin][skip ci] prepare release 17.70 2022-08-06 00:37:28 +00:00
dependabot[bot]
ab0d482179 Bump postgresql from 42.4.0 to 42.4.1 (#1271) 2022-08-06 00:01:23 +00:00
Travis CI User
5fed5292d9 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-05 09:38:41 +00:00
Travis CI User
1e8944a310 [maven-release-plugin][skip ci] prepare release 17.69 2022-08-05 09:38:38 +00:00
Kristian Dimitrov
b97b6751cc ACS-3381: Initial commit (#1272) 2022-08-05 10:04:17 +01:00
Tom Page
af97aca661 ACS-3360 GET APIs for rule sets. (#1263)
ACS-3360 GET APIs for rule sets.

Move RulesImpl and RuleSetsImpl into their own package.
Split out node validation into a new class.
2022-08-04 17:27:51 +02:00
Travis CI User
368acf4724 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-04 05:56:52 +00:00
Travis CI User
2341f0290e [maven-release-plugin][skip ci] prepare release 17.68 2022-08-04 05:56:49 +00:00
pzurek
2e4f5d5726 Revert "Bump dependency.camel.version from 3.15.0 to 3.18.0 (#1200)"
This reverts commit 2285dc1ecb.
2022-08-04 07:21:17 +02:00
Travis CI User
be118c25ba [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-03 09:43:05 +00:00
Travis CI User
601b743388 [maven-release-plugin][skip ci] prepare release 17.67 2022-08-03 09:43:03 +00:00
Travis CI User
3c3c3b2666 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-03 07:27:27 +00:00
Travis CI User
b671e17f03 [maven-release-plugin][skip ci] prepare release 17.66 2022-08-03 07:27:24 +00:00
dependabot[bot]
a08b134ec2 Bump restapi from 1.99 to 1.100 (#1270) 2022-08-03 06:53:32 +00:00
Travis CI User
9795349f9b [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-02 13:48:18 +00:00
Travis CI User
f120ba3a87 [maven-release-plugin][skip ci] prepare release 17.65 2022-08-02 13:48:15 +00:00
dependabot[bot]
2285dc1ecb Bump dependency.camel.version from 3.15.0 to 3.18.0 (#1200)
Bumps `dependency.camel.version` from 3.15.0 to 3.18.0.

Updates `camel-core` from 3.15.0 to 3.18.0

Updates `camel-spring-xml` from 3.15.0 to 3.18.0

Updates `camel-activemq` from 3.15.0 to 3.18.0

Updates `camel-amqp` from 3.15.0 to 3.18.0

Updates `camel-jackson` from 3.15.0 to 3.18.0

Updates `camel-directvm` from 3.15.0 to 3.18.0

Updates `camel-direct` from 3.15.0 to 3.18.0

Updates `camel-management` from 3.15.0 to 3.18.0

Updates `camel-mock` from 3.15.0 to 3.18.0

---
updated-dependencies:
- dependency-name: org.apache.camel:camel-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.camel:camel-spring-xml
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.camel:camel-activemq
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.camel:camel-amqp
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.camel:camel-jackson
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.camel:camel-directvm
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.camel:camel-direct
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.camel:camel-management
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.camel:camel-mock
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-02 15:04:54 +02:00
Travis CI User
cbded8f967 [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-02 13:02:59 +00:00
Travis CI User
5e3ee41fce [maven-release-plugin][skip ci] prepare release 17.64 2022-08-02 13:02:57 +00:00
Maciej Pichura
6c9163ce65 ACS-3227: REST API TAS tests for create rule with consumer role. (#1262) 2022-08-02 14:33:08 +02:00
krdabrowski
8a79d3bed1 ACS-3229: Rules v1 REST API - Get rule definition - mapping of conditions (#1252)
ACS-3229: Rules v1 REST API - Get rule definition
- adding mapping of "conditions"
- fixing trigger constants - uppercase -> lowercase
- fixing booleanMode - uppercase -> lowercase
2022-08-02 14:10:52 +02:00
Travis CI User
f1c588f1da [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-02 08:54:43 +00:00
Travis CI User
f38902ede9 [maven-release-plugin][skip ci] prepare release 17.63 2022-08-02 08:54:40 +00:00
dependabot[bot]
5f1cf5ef60 Bump docker-maven-plugin from 0.40.1 to 0.40.2 (#1267) 2022-08-02 08:01:57 +00:00
Travis CI User
2a41c1f14a [maven-release-plugin][skip ci] prepare for next development iteration 2022-08-01 09:31:23 +00:00
Travis CI User
4f0cbd7206 [maven-release-plugin][skip ci] prepare release 17.62 2022-08-01 09:31:20 +00:00
dependabot[bot]
0823d5319c Bump restapi from 1.97 to 1.99 (#1265) 2022-08-01 08:42:43 +00:00
krdabrowski
001e7a4bff ACS-3229: Rules v1 REST API - Get rule definition - mapping of actions (#1245)
ACS-3229: Rules v1 REST API - Get rule definition
- adding mapping of "actions"
2022-08-01 10:35:52 +02:00
Domenico Sibilio
aba89218e6 ACS-3347 Upgrade to Java 17 (#1253)
* Addressing JDK-8189366, JDK-8212114, JDK-8208487, changes to default legacy Locale ISO Code conversions and changes to JVM arguments to allow illegal reflective access
2022-08-01 09:30:56 +02:00
Travis CI User
e533af4ecb [maven-release-plugin][skip ci] prepare for next development iteration 2022-07-31 00:09:26 +00:00
Travis CI User
4a7046211b [maven-release-plugin][skip ci] prepare release 17.61 2022-07-31 00:09:24 +00:00
Alfresco CI User
48e902c556 [force] Force release for 2022-07-31. 2022-07-31 00:04:00 +00:00
Vítor Moreira
e178428624 MNT-22979: removed unused commons-dbcp artefact from activiti (#1231) 2022-07-29 16:08:13 +01:00
Maciej Pichura
7b4f7c9174 ACS-3345 e2e REST API TAS tests delete rule (#1256)
* ACS-3345: REST API TAS tests for delete rule.

* ACS-3345: REST API TAS tests for delete rule.

* ACS-3345: REST API TAS tests for delete rule.

* ACS-3345: Fixing the naming.

* ACS-3345: REST API TAS tests for delete rule.
2022-07-29 14:29:56 +02:00
dependabot[bot]
d84424ee5b Bump dependency.spring.version from 5.3.21 to 5.3.22 (#1221) 2022-07-29 12:24:41 +00:00
dependabot[bot]
a4ad5f9211 Bump utility from 3.0.48 to 3.0.49 (#1229) 2022-07-29 11:57:56 +00:00
dependabot[bot]
9fbdc61d3c Bump maven-assembly-plugin from 3.4.1 to 3.4.2 (#1248) 2022-07-29 10:02:47 +00:00
dependabot[bot]
7db6d372da Bump maven-resources-plugin from 3.2.0 to 3.3.0 (#1246) 2022-07-29 08:28:12 +00:00
dependabot[bot]
c334f14cd2 Bump groovy from 3.0.11 to 3.0.12 (#1247) 2022-07-29 08:23:39 +00:00
dependabot[bot]
d584b3c1a3 Bump mysql-connector-java from 8.0.29 to 8.0.30 (#1250) 2022-07-29 08:15:56 +00:00
Travis CI User
b06a74c5cb [maven-release-plugin][skip ci] prepare for next development iteration 2022-07-28 16:25:00 +00:00
Travis CI User
5b723e9176 [maven-release-plugin][skip ci] prepare release 17.60 2022-07-28 16:24:56 +00:00
Kristian Dimitrov
bf69340e4b ACS-2827: Initial commit (#1259) 2022-07-28 16:50:43 +01:00
Travis CI User
b6aeac0c4e [maven-release-plugin][skip ci] prepare for next development iteration 2022-07-28 14:37:18 +00:00
Travis CI User
c1da01ba6e [maven-release-plugin][skip ci] prepare release 17.59 2022-07-28 14:37:15 +00:00
Sara
ecb0d9a329 Feature/acs 3122 update tomcat to rocky linux8 (#1258)
* update tomcat base image to rockylinux8

* add dockerfile to dependabot

* update packages for rockylinux8

* fix time zone double quotes

* correct dependabot indents

* correct dependabot indents

* corrected nbr pull requests
2022-07-28 15:02:39 +01:00
Travis CI User
c3189adf9f [maven-release-plugin][skip ci] prepare for next development iteration 2022-07-28 11:48:42 +00:00
Travis CI User
8a7b8a7a54 [maven-release-plugin][skip ci] prepare release 17.58 2022-07-28 11:48:39 +00:00
Sara
3d35eed39c Feature/acs 3122 update tomcat to rocky linux8 (#1255)
* update tomcat base image to rockylinux8

* add dockerfile to dependabot

* update packages for rockylinux8
2022-07-28 12:15:00 +01:00
Travis CI User
37afef846f [maven-release-plugin][skip ci] prepare for next development iteration 2022-07-28 08:16:48 +00:00
Travis CI User
57a3fbd2d5 [maven-release-plugin][skip ci] prepare release 17.57 2022-07-28 08:16:46 +00:00
Tom Page
378347ae35 ACS-3214 Unit tests for update rule API. (#1257) 2022-07-28 08:12:08 +01:00
Travis CI User
fc8ec4f993 [maven-release-plugin][skip ci] prepare for next development iteration 2022-07-27 15:51:33 +00:00
120 changed files with 10727 additions and 2324 deletions

View File

@@ -158,3 +158,9 @@ updates:
- "8.16"
registries:
- maven-repository-artifacts-alfresco-com-nexus-content-groups-int
- package-ecosystem: "docker"
directory: "packaging/docker-alfresco/"
schedule:
interval: "daily"
time: "22:00"
timezone: Africa/Abidjan

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

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

View File

@@ -1,7 +1,7 @@
---
dist: focal
language: java
jdk: openjdk11
jdk: openjdk17
services:
- docker

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>17.56</version>
<version>17.102-SNAPSHOT</version>
</parent>
<modules>
@@ -30,16 +30,20 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- Keeping illegal-access=permit for Java 11 compatibility, even though it has no effect on JDK 17 -->
<argLine>
--illegal-access=permit
--add-opens=java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<!-- Keeping illegal-access=permit for Java 11 compatibility, even though it has no effect on JDK 17 -->
<configuration>
<argLine>
--illegal-access=permit
--add-opens=java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</plugin>

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
<version>17.56</version>
<version>17.102-SNAPSHOT</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

@@ -74,4 +74,27 @@ public class RecordFoldersAPI extends BaseAPI
return null;
}
public HttpResponse postFolderAction(String user, String password, JSONObject requestParams, String recordFolder) {
String recNodeRef = getNodeRefSpacesStore() + contentService.getNodeRef(user, password, RM_SITE_ID, recordFolder);
try {
requestParams.put("nodeRef", recNodeRef);
return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API);
}
catch (Exception error) {
LOGGER.error("Unable to extract response parameter", error);
}
return null;
}
public HttpResponse postRecordAction(String user, String password, JSONObject requestParams, String recordId) {
try {
requestParams.put("nodeRef", recordId);
return doPostJsonRequest(user, password, SC_OK, requestParams, RM_ACTIONS_API);
}
catch (JSONException error) {
LOGGER.error("Unable to extract response parameter", error);
}
return null;
}
}

View File

@@ -53,9 +53,12 @@ import static org.springframework.http.HttpStatus.OK;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Date;
import java.util.TimeZone;
import java.util.stream.Collectors;
import lombok.Getter;
@@ -91,6 +94,7 @@ 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.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.testng.annotations.BeforeClass;
@@ -121,6 +125,8 @@ public class BaseRMRestTest extends RestTest
@Getter(value = PROTECTED)
private SearchAPI searchApi;
protected static final String iso8601_DateFormat="yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
/**
* Asserts the given status code
*
@@ -628,8 +634,8 @@ public class BaseRMRestTest extends RestTest
* Returns search results for the given search term
*
* @param user
* @param term
* @param query language
* @param q
* @param queryLanguage language
* @return
* @throws Exception
*/
@@ -956,5 +962,34 @@ public class BaseRMRestTest extends RestTest
return false;
}
}
/**
* Helper method to get the Previous Date in the YYYY-MM-ddTHH:mm:ss.SSSXXX format
* @param previousDays number of previous days while calculating the date as output
* @return previousDate as String in the ISO 8601 Date Format
*/
protected String getIso8601Date(int previousDays) {
Date date = new Date(System.currentTimeMillis());
Date previousDate = new Date(date.getTime() - previousDays);
// Conversion
SimpleDateFormat sdf= new SimpleDateFormat(iso8601_DateFormat);;
sdf.setTimeZone(TimeZone.getDefault());
return sdf.format(previousDate);
}
/**
* Helper method to provide the Edited Disposition Date Json
* The Edited Disposition Date is modified to previous date so that CUTOFF & DESTROY Steps will be enabled
* @return JsonObject with the format {"name":"editDispositionActionAsOfDate","params":{"asOfDate":{"iso8601":"Previous Date"}}}
*/
protected JSONObject editDispositionDateJson() {
JSONObject requestParams = new JSONObject();
requestParams.put("name","editDispositionActionAsOfDate");
JSONObject params = new JSONObject();
requestParams.put("params",params);
JSONObject asOfDate = new JSONObject();
params.put("asOfDate",asOfDate);
asOfDate.put("iso8601",getIso8601Date(1));
return requestParams;
}
}

View File

@@ -0,0 +1,211 @@
/*
* #%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.core.v0.BaseAPI;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
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.rest.v0.service.RMAuditService;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
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.model.audit.AuditEvents.DELETE_PERSON;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.LOGIN_SUCCESSFUL;
import static org.alfresco.rest.rm.community.records.SearchRecordsTests.*;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.junit.Assert.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
/**
* Audit Access tests
* @author Kavit Shah
*/
public class AuditAccessTests extends BaseRMRestTest {
private Optional<UserModel> deletedUser;
private final String TEST_PREFIX = generateTestPrefix(AuditAccessTests.class);
private static final String DELETE_USER_EVENT = "Delete User";
private final String record1 = TEST_PREFIX + "RM-2967 uploaded record";
private final String classifiedRecord = TEST_PREFIX + "RM-2967 classified record";
private final String folderName = TEST_PREFIX + "RM-2967 folder";
private final String categoryName = TEST_PREFIX + "RM-2967 category";
private final String editedCategoryName = "edited " + categoryName;
private final String editedFolderName = "edited " + folderName;
private final String editedRecordName = "edited " + record1;
private final String login_successfull = "Login Successful";
private RecordCategory categoryAll;
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired
private RecordsAPI recordsAPI;
@Autowired
private RMAuditService rmAuditService;
@Test(priority = 1)
@AlfrescoTest(jira = "RM-2967")
public void deleteRMUsersShowFullAuditTest() {
createTestPrecondition();
updateCategoryMetadata();
updateFolderMetadata();
updateRecordMetadata();
// delete record category and folder with rm_admin_deleted
rmRolesAndActionsAPI.deleteAllItemsInContainer(deletedUser.get().getUsername(), deletedUser.get().getPassword(),
RM_SITE_ID, editedFolderName);
rmRolesAndActionsAPI.deleteAllItemsInContainer(deletedUser.get().getUsername(), deletedUser.get().getPassword(),
RM_SITE_ID, editedCategoryName);
// delete the user
Optional.of(deletedUser).ifPresent(x -> getDataUser().deleteUser(x.get()));
//check for RM-5235 fix
List<AuditEntry> auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getDataUser().usingAdmin().getAdminUser(),
DELETE_PERSON);
assertTrue("Delete user event not found in the audit log.", auditEntries.stream().anyMatch(
auditEntry -> auditEntry.getEvent().equals(DELETE_USER_EVENT)));
}
@Test(priority = 2)
public void filterEventsByLoginSuccessful()
{
createRMSiteIfNotExists();
List<AuditEntry> auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getDataUser().usingAdmin().getAdminUser(),
LOGIN_SUCCESSFUL);
assertFalse("Audit results should contain at least one Login Successful event",
auditEntries.isEmpty());
assertTrue("Audit results contain only Login Successful events",
auditEntries.stream()
.allMatch(e -> e.getEvent().startsWith(LOGIN_SUCCESSFUL.toString()) || e.getEvent().startsWith(login_successfull)));
}
/**
* Creates the required precondition for the test
* <p/>
* See Precondition in current class JavaDoc
*/
private void createTestPrecondition() {
createRMSiteIfNotExists();
// create "rm deleted user" user if it does not exist and assign it to RM Administrator role
createDeletedUser();
// create category and folder
categoryAll = createCategoryIfDoesNotExist(categoryName,deletedUser.get());
createRecordFolderInCategory(folderName,categoryAll,deletedUser.get());
// upload an electronic record
recordsAPI.uploadElectronicRecord(deletedUser.get().getUsername(), deletedUser.get().getPassword(), getDefaultElectronicRecordProperties(record1), folderName, CMISUtil.DocumentType.TEXT_PLAIN);
// upload another electronic record and classify it
recordsAPI.uploadElectronicRecord(deletedUser.get().getUsername(), deletedUser.get().getPassword(), getDefaultElectronicRecordProperties(classifiedRecord), folderName, CMISUtil.DocumentType.TEXT_PLAIN);
}
private void createDeletedUser() {
// create Deleted User
deletedUser = Optional.ofNullable(getDataUser().createRandomTestUser());
rmRolesAndActionsAPI.assignRoleToUser(
getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(),
deletedUser.get().getUsername(),
ADMIN
);
}
private void updateCategoryMetadata() {
HashMap<BaseAPI.RMProperty, String> categoryProperties = new HashMap<>();
categoryProperties.put(BaseAPI.RMProperty.NAME, editedCategoryName);
categoryProperties.put(BaseAPI.RMProperty.TITLE, "edited " + TITLE);
categoryProperties.put(BaseAPI.RMProperty.DESCRIPTION, "edited " + DESCRIPTION);
// edit some category's properties
String categoryNodeRef = NODE_PREFIX + rmRolesAndActionsAPI.getItemNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), "/" + categoryName);
rmRolesAndActionsAPI.updateMetadata(deletedUser.get().getUsername(), deletedUser.get().getPassword(), categoryNodeRef, categoryProperties);
}
private void updateFolderMetadata() {
HashMap<BaseAPI.RMProperty, String> folderProperties = new HashMap<>();
folderProperties.put(BaseAPI.RMProperty.NAME, editedFolderName);
folderProperties.put(BaseAPI.RMProperty.TITLE, "edited " + TITLE);
folderProperties.put(BaseAPI.RMProperty.DESCRIPTION, "edited " + DESCRIPTION);
// edit some folder's properties
String folderNodeRef = NODE_PREFIX + rmRolesAndActionsAPI.getItemNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), "/" + editedCategoryName + "/" + folderName);
rmRolesAndActionsAPI.updateMetadata(deletedUser.get().getUsername(), deletedUser.get().getPassword(), folderNodeRef, folderProperties);
}
private void updateRecordMetadata() {
HashMap<BaseAPI.RMProperty, String> recordProperties = new HashMap<>();
recordProperties.put(BaseAPI.RMProperty.NAME, editedRecordName);
recordProperties.put(BaseAPI.RMProperty.TITLE, "edited " + TITLE);
recordProperties.put(BaseAPI.RMProperty.AUTHOR, "edited author");
recordProperties.put(BaseAPI.RMProperty.DESCRIPTION, "edited " + DESCRIPTION);
// edit some record's properties
String recordName = recordsAPI.getRecordFullName(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), editedFolderName, record1);
String recordNodeRef = NODE_PREFIX + rmRolesAndActionsAPI.getItemNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), "/" + editedCategoryName + "/" + editedFolderName + "/" + recordName);
rmRolesAndActionsAPI.updateMetadata(deletedUser.get().getUsername(), deletedUser.get().getPassword(), recordNodeRef, recordProperties);
}
private RecordCategory createCategoryIfDoesNotExist(String CATEGORY_ALL, UserModel deletedUser) {
return createRootCategory(deletedUser, CATEGORY_ALL);
}
private RecordCategoryChild createRecordFolderInCategory(String FOLDER_SEARCH, RecordCategory recordCategory, UserModel deletedUser) {
return createFolder(deletedUser, recordCategory.getId(), FOLDER_SEARCH);
}
private Map<BaseAPI.RMProperty, String> getDefaultElectronicRecordProperties(String recordName) {
Map<BaseAPI.RMProperty, String> defaultProperties = new HashMap<>();
defaultProperties.put(BaseAPI.RMProperty.NAME, recordName);
defaultProperties.put(BaseAPI.RMProperty.TITLE, TITLE);
defaultProperties.put(BaseAPI.RMProperty.DESCRIPTION, DESCRIPTION);
defaultProperties.put(BaseAPI.RMProperty.CONTENT, TEST_CONTENT);
return defaultProperties;
}
}

View File

@@ -0,0 +1,104 @@
/*
* #%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.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.rules.ActionsOnRule;
import org.alfresco.rest.rm.community.model.rules.RuleDefinition;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.RulesAPI;
import org.alfresco.test.AlfrescoTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
import java.util.Collections;
import static org.alfresco.rest.core.v0.BaseAPI.NODE_PREFIX;
import static org.alfresco.rest.rm.community.base.TestData.ELECTRONIC_RECORD_NAME;
import static org.alfresco.rest.rm.community.base.TestData.NONELECTRONIC_RECORD_NAME;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.*;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.*;
public class BasicRulesIntegrationTests extends BaseRMRestTest {
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
private final static String title = "Rule to complete";
private final static String description = "Rule to describe";
private final String TEST_PREFIX = generateTestPrefix(CreateCategoriesTests.class);
private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
@Autowired
private RulesAPI rulesAPI;
@Test
@AlfrescoTest(jira = "RM-2794")
public void basicRulesIntegration() {
STEP("Create the RM site if doesn't exist");
createRMSiteIfNotExists();
STEP("Create RM Admin user");
rmRolesAndActionsAPI.createUserAndAssignToRole(getAdminUser().getUsername(), getAdminUser().getPassword(), RM_ADMIN,
getAdminUser().getPassword(),
"Administrator");
STEP("Create record categories and record folders");
RecordCategory Category = createRootCategory(getRandomName("recordCategory"));
String recordFolder1 = createRecordFolder(Category.getId(), getRandomName("recFolder")).getId();
//create a rule for completing a record
RuleDefinition ruleDefinition = RuleDefinition.createNewRule().title("name").description("description1")
.applyToChildren(true).title(title)
.actions(Collections.singletonList(ActionsOnRule.COMPLETE_RECORD.getActionValue()));
rulesAPI.createRule(getAdminUser().getUsername(), getAdminUser().getPassword(), NODE_PREFIX + Category.getId(), ruleDefinition);
RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI();
//create two electronic record in record folder
String electronicRecordId1 = createElectronicRecord(recordFolder1, ELECTRONIC_RECORD_NAME).getId();
String electronicRecordId2 = createElectronicRecord(recordFolder1, ELECTRONIC_RECORD_NAME).getId();
assertStatusCode(CREATED);
// Update the rules for record Category
rulesAPI.updateRule(getAdminUser().getUsername(), getAdminUser().getPassword(),
NODE_PREFIX + Category.getId(), ruleDefinition.description("description").id(description));
//Delete the root category and rules
deleteRecordCategory(Category.getId());
rulesAPI.deleteAllRulesOnContainer(getAdminUser().getUsername(), getAdminUser().getPassword(), NODE_PREFIX + Category.getId());
}
}

View File

@@ -0,0 +1,125 @@
/*
* #%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.fileplan.FilePlan;
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.test.AlfrescoTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
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.getRandomAlphanumeric;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.junit.Assert.assertFalse;
import static org.springframework.http.HttpStatus.OK;
import static org.testng.Assert.assertEquals;
public class CreateCategoriesTests extends BaseRMRestTest {
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
private RecordCategory rootCategory;
private final String TEST_PREFIX = generateTestPrefix(CreateCategoriesTests.class);
private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
private RecordCategory Category1;
private RecordCategory Category2;
private RecordCategory SubCategory1;
private RecordCategory SubCategory2;
@BeforeClass(alwaysRun = true)
public void preconditionForCreateCategoriesTests()
{
STEP("Create the RM site if doesn't exist");
createRMSiteIfNotExists();
STEP("Create RM Admin user");
rmRolesAndActionsAPI.createUserAndAssignToRole(getAdminUser().getUsername(), getAdminUser().getPassword(), RM_ADMIN,
getAdminUser().getPassword(),
"Administrator");
STEP("Create two category");
Category1 = createRootCategory(getRandomName("Category1"));
Category2= createRootCategory(getRandomName("Category2"));
STEP("Create Sub category");
RecordCategoryChild subCategory1 = createRecordCategory(Category1.getId(), getRandomName("subCategory1"));
RecordCategoryChild subCategory2 = createRecordCategory(Category2.getId(), getRandomName("subCategory2"));
}
@Test @AlfrescoTest(jira = "RM-2756")
public void createCategories() throws Exception {
FilePlan filePlan = getRestAPIFactory().getFilePlansAPI().getFilePlan(FILE_PLAN_ALIAS);
STEP("copy category 1 to File Plan.");
getRestAPIFactory().getNodeAPI(toContentModel(Category1.getId())).copy(createBodyForMoveCopy(filePlan.getId()));
STEP("copy category 1 to category 2");
getRestAPIFactory().getNodeAPI(toContentModel(Category1.getId())).copy(createBodyForMoveCopy(Category2.getId()));
String categoryName = "Category name " + getRandomAlphanumeric();
String categoryTitle = "Category title " + getRandomAlphanumeric();
// Create the root record category
RecordCategory Category1 = createRootCategory(categoryName, categoryTitle);
String newCategoryName = "Rename " + categoryName;
// Build the properties which will be updated
RecordCategory recordCategoryUpdated = Category1.builder().name(newCategoryName).build();
// Update the record category
RecordCategory renamedRecordCategory = getRestAPIFactory().getRecordCategoryAPI().updateRecordCategory(recordCategoryUpdated,Category1.getId());
// Verify the status code
assertStatusCode(OK);
// verify renamed component and editTitle component still has this parent
assertEquals(renamedRecordCategory.getParentId(), filePlan.getId());
STEP("move category 1 edited copy to File Plan");
getRestAPIFactory().getNodeAPI(toContentModel(renamedRecordCategory.getId())).move(createBodyForMoveCopy(filePlan.getId()));
assertStatusCode(OK);
// delete All the categories
deleteRecordCategory(Category1.getId());
deleteRecordCategory(Category2.getId());
}
}

View File

@@ -0,0 +1,147 @@
/*
* #%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.common.ReviewPeriod;
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.RecordFolder;
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolderProperties;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordCategoryAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.test.AlfrescoTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
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.getRandomAlphanumeric;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.*;
public class CreateFoldersTests extends BaseRMRestTest {
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
private final String TEST_PREFIX = generateTestPrefix(CreateCategoriesTests.class);
private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
private RecordCategory Category1;
private RecordCategory Category2;
private RecordCategoryChild recordCategoryChild;
@BeforeClass(alwaysRun = true)
public void preconditionForCreateFolderTests() {
STEP("Create the RM site if doesn't exist");
createRMSiteIfNotExists();
STEP("Create RM Admin user");
rmRolesAndActionsAPI.createUserAndAssignToRole(getAdminUser().getUsername(), getAdminUser().getPassword(), RM_ADMIN,
getAdminUser().getPassword(),
"Administrator");
STEP("Create two category");
Category1 = createRootCategory(getRandomName("Category1"));
Category2 = createRootCategory(getRandomName("Category2"));
// Create a record folder inside the category 1
recordCategoryChild = createRecordFolder(Category1.getId(), getRandomName("recFolder"));
}
@Test
@AlfrescoTest(jira = "RM-2757")
public void createFolders() throws Exception {
// Create record category first
String folderDescription = "The folder description is updated" + getRandomAlphanumeric();
String folderName = "The folder name is updated" + getRandomAlphanumeric();
String folderTitle = "Update title " + getRandomAlphanumeric();
String location = "Location "+ getRandomAlphanumeric();
// Create the record folder properties to update
RecordFolder recordFolder = RecordFolder.builder()
.name(folderName)
.properties(RecordFolderProperties.builder()
.title(folderTitle)
.description(folderDescription)
.vitalRecordIndicator(true)
.reviewPeriod(new ReviewPeriod("month","1"))
.location(location)
.build())
.build();
// Update the record folder
RecordFolder updatedRecordFolder = getRestAPIFactory().getRecordFolderAPI().updateRecordFolder(recordFolder, recordCategoryChild.getId());
// Check the Response Status Code
assertStatusCode(OK);
STEP("copy updated Record in category 1 and category 2");
getRestAPIFactory().getNodeAPI(toContentModel(updatedRecordFolder.getId())).copy(createBodyForMoveCopy(Category1.getId()));
//assertStatusCode(OK);
getRestAPIFactory().getNodeAPI(toContentModel(updatedRecordFolder.getId())).copy(createBodyForMoveCopy(Category2.getId()));
//assertStatusCode(OK);
// Delete the Updated folder
RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI();
String recordFolderId = updatedRecordFolder.getId();
recordFolderAPI.deleteRecordFolder(recordFolderId);
// Check the response status code
assertStatusCode(NO_CONTENT);
// Check the record folder is not found
recordFolderAPI.getRecordFolder(recordFolderId);
// Check the response status code
assertStatusCode(NOT_FOUND);
STEP("move updated Record from category 1 to category 2");
getRestAPIFactory().getNodeAPI(toContentModel(updatedRecordFolder.getId())).move(createBodyForMoveCopy(Category2.getId()));
// move category 2 to category 1
getRestAPIFactory().getNodeAPI(toContentModel(Category2.getId())).move(createBodyForMoveCopy(Category1.getId()));
// Delete the record category
RecordCategoryAPI recordCategoryAPI = getRestAPIFactory().getRecordCategoryAPI();
String recordCategoryId = Category1.getId();
recordCategoryAPI.deleteRecordCategory(recordCategoryId);
// Verify the status code
assertStatusCode(NO_CONTENT);
}
}

View File

@@ -0,0 +1,122 @@
/*
* #%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 lombok.Getter;
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.rules.ActionsOnRule;
import org.alfresco.rest.rm.community.model.rules.RuleDefinition;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildEntry;
import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledContainerAPI;
import org.alfresco.rest.v0.RulesAPI;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.data.DataContent;
import org.alfresco.utility.data.DataSite;
import org.alfresco.utility.data.DataUserAIS;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import static lombok.AccessLevel.PROTECTED;
import static org.alfresco.rest.core.v0.BaseAPI.NODE_PREFIX;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.CREATED;
public class DeclareDocsAsRecordsOnUpdateRuleNewVersionTests extends BaseRMRestTest {
@Autowired
private DataSite dataSite;
private SiteModel publicSite;
private RecordCategory recordCategory;
@Autowired
private RulesAPI rulesAPI;
@Autowired
protected DataContent dataContent;
@Autowired
@Getter(value = PROTECTED)
protected DataUserAIS dataUser;
private final static String title = "Rule to convert document as record";
@BeforeClass (alwaysRun = true)
public void setUp()
{
publicSite = dataSite.usingAdmin().createPublicRandomSite();
recordCategory = createRootCategory(getRandomName("recordCategory"));
}
@Test
@AlfrescoTest(jira = "RM-1521")
public void declareDocsAsRecordsOnUpdateRuleNewVersion() {
FolderModel testFolder;
STEP("Create test collaboration site to store documents in.");
publicSite = dataSite.usingAdmin().createPublicRandomSite();
STEP("Create a record folder with a DECLARE_AS_RECORD");
RecordCategoryChild folderWithRule = createFolder(recordCategory.getId(), getRandomName("recordFolder"));
RuleDefinition ruleDefinition = RuleDefinition.createNewRule().title("name").description("description")
.applyToChildren(true)
.actions(Collections.singletonList(ActionsOnRule.DECLARE_AS_RECORD.getActionValue()));
rulesAPI.createRule(getAdminUser().getUsername(), getAdminUser().getPassword(), NODE_PREFIX + folderWithRule.getId(), ruleDefinition);
STEP("Create a document in the collaboration site");
FileModel testFile = dataContent.usingSite(publicSite)
.usingAdmin()
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
assertStatusCode(CREATED);
// verify the declared record is in Unfilled Records folder
UnfiledContainerAPI unfiledContainersAPI = getRestAPIFactory().getUnfiledContainersAPI();
List<UnfiledContainerChildEntry> matchingRecords = unfiledContainersAPI.getUnfiledContainerChildren(UNFILED_RECORDS_CONTAINER_ALIAS)
.getEntries()
.stream()
.filter(e -> e.getEntry().getId().equals(testFile.getNodeRefWithoutVersion()))
.collect(Collectors.toList());
//delete rm items
deleteRecordCategory(recordCategory.getId());
STEP("Delete the record.");
//delete created collaboration site
dataSite.deleteSite(publicSite);
}
}

View File

@@ -0,0 +1,238 @@
/*
* #%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.v0.RecordCategoriesAPI;
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.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.concurrent.atomic.AtomicReference;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
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.rest.rm.community.utils.CoreUtil.toContentModel;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.test.util.AssertionErrors.assertTrue;
import static org.testng.Assert.*;
public class FileAsRecordTests extends BaseRMRestTest {
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);
private UserModel nonRMuser,rmManager;
private SiteModel testSite;
private FileModel document, documentDeclared;
private RecordCategory category_manager, category_admin;
private RecordCategoryChild folder_admin, folder_manager ;
@Autowired
private DataSite dataSite;
@Autowired
private DataContent dataContent;
@Autowired
private RoleService roleService;
@Autowired
private RecordCategoriesAPI recordCategoriesAPI;
/**
* Create preconditions:
* <pre>
* 1. RM site is created
* 2. Two users: user without RM role and a user with RM manager role
* 3. Two Record categories with one folder each
* 4. User with RM MANAGER role has Filling permission over one category
* </pre>
*/
@BeforeClass(alwaysRun = true)
public void preconditionForFileAsRecordRecordTests()
{
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);
}
/**
* Given I have selected the record folder I want to file my declared record to
* When I confirm the action
* Then the dialog closes
* And the document is now shown as a record in the collaboration site
* And if I navigated to the record folder, as any user who had the right permissions, then I would see the
* record filed
*/
@Test
@AlfrescoTest(jira = "RM-6780")
public void checkFileAsRecordToRecordFolder() throws Exception {
AtomicReference<RecordFolderCollection> apiChildren = new AtomicReference<>();
STEP("Create a document with the user with RM role");
documentDeclared = dataContent.usingSite(testSite).usingUser(rmManager)
.createContent(new FileModel("checkDeclareAndFileToRecordFolder", FileType.TEXT_PLAIN));
STEP("Declare and file into a record folder the document uploaded");
getRestAPIFactory().getActionsAPI(rmManager).declareAndFile(documentDeclared,
Utility.buildPath(CATEGORY_MANAGER, FOLDER_MANAGER));
STEP("Check the file is a record within the collaboration site");
try
{
Utility.sleep(1000, 40000, () ->
{
JSONObject collaboratorSearchJson = getSearchApi().liveSearchForDocuments(rmManager.getUsername(),
rmManager.getPassword(),
documentDeclared.getName());
assertTrue("Rm Manager not able to find the document.", collaboratorSearchJson.getJSONArray("items").length() != 0);
});
}
catch (InterruptedException e)
{
fail("InterruptedException received while waiting for results.");
}
STEP("Check the record is filed into the record folder.");
// Get children from API
// List children from API
try
{
Utility.sleep(1000, 40000, () ->
{
apiChildren.set((RecordFolderCollection) getRestAPIFactory()
.getRecordFolderAPI(rmManager).getRecordFolderChildren(folder_manager.getId(), "include=properties")
.assertThat().entriesListIsNotEmpty().assertThat().entriesListIsNotEmpty());
});
}
catch (InterruptedException e)
{
fail("InterruptedException received while waiting for results.");
}
assertEquals(apiChildren.get()
.getEntries()
.get(0)
.getEntry()
.getProperties()
.getOriginalName(),documentDeclared.getName());
}
/**
* Given I have selected the "File As Record" action
* When I confirm the action without selecting a location to file to
* Then the record is declared in the unfiled folder
*/
@Test
@AlfrescoTest (jira = "RM-6780")
public void fileAsRecordToUnfiledRecordFolder() throws Exception {
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");
}
@AfterClass(alwaysRun = true)
public void cleanUpForFileAsRecordRecordTests() {
STEP("Delete the collaboration site");
dataSite.usingUser(nonRMuser).deleteSite(testSite);
STEP("Empty the trashcan.");
restClient.authenticateUser(nonRMuser).withCoreAPI().usingTrashcan().deleteNodeFromTrashcan(toContentModel(testSite.getId()));
getRestAPIFactory()
.getUnfiledContainersAPI(rmManager)
.getUnfiledContainerChildren(UNFILED_RECORDS_CONTAINER_ALIAS)
.getEntries()
.stream()
.forEach(x -> getRestAPIFactory()
.getRecordsAPI()
.deleteRecord(x.getEntry().getId()));
STEP("Cleanup Documents inside folders");
STEP("Delete folders");
getRestAPIFactory().getRecordFolderAPI().deleteRecordFolder(folder_admin.getId());
getRestAPIFactory().getRecordFolderAPI().deleteRecordFolder(folder_manager.getId());
STEP("Delete categories");
recordCategoriesAPI.deleteCategory(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), category_manager.getName());
recordCategoriesAPI.deleteCategory(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), category_admin.getName());
STEP("Delete Users");
dataUser.deleteUser(nonRMuser);
dataUser.deleteUser(rmManager);
}
}

View File

@@ -0,0 +1,108 @@
/*
* #%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.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.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.Test;
import static org.alfresco.rest.rm.community.model.recordcategory.RetentionPeriodProperty.CREATED_DATE;
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;
public class FoldersDispositionScheduleTests extends BaseRMRestTest {
private RecordCategory Category1;
@Autowired
private DispositionScheduleService dispositionScheduleService;
@Autowired
private RecordFoldersAPI recordFoldersAPI;
private final String TEST_PREFIX = generateTestPrefix(FoldersDispositionScheduleTests.class);
private final String folderDisposition = TEST_PREFIX + "RM-2937 folder ghosting";
private final String electronicRecord = "RM-2937 electronic 2 record";
private final String nonElectronicRecord = "RM-2937 non-electronic record";
@BeforeClass(alwaysRun = true)
private void setUp(){
STEP("Create the RM site if doesn't exist");
createRMSiteIfNotExists();
STEP("Create record category");
Category1 = createRootCategory(getRandomName("Title"));
}
@Test
@AlfrescoTest (jira = "RM-2937")
public void foldersDispositionScheduleWithGhosting() {
//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());
//create folders
RecordCategoryChild FOLDER_DESTROY = createFolder(getAdminUser(),Category1.getId(),folderDisposition);
Record elRecord = createElectronicRecord(FOLDER_DESTROY.getId(),electronicRecord);
Record nonElRecord = createNonElectronicRecord(FOLDER_DESTROY.getId(),nonElectronicRecord);
// complete records
completeRecord(elRecord.getId());
completeRecord(nonElRecord.getId());
// 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());
}
@AfterMethod(alwaysRun = true)
private void deletePreconditions() {
deleteRecordCategory(Category1.getId());
}
}

View File

@@ -0,0 +1,116 @@
/*
* #%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.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.RecordFoldersAPI;
import org.alfresco.rest.v0.service.DispositionScheduleService;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.Utility;
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.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.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
public class FoldersDispositionScheduleWithoutGhostRecordTests extends BaseRMRestTest {
private RecordCategory Category1;
@Autowired
private DispositionScheduleService dispositionScheduleService;
@Autowired
private RecordFoldersAPI recordFoldersAPI;
private final String TEST_PREFIX = generateTestPrefix(FoldersDispositionScheduleWithoutGhostRecordTests.class);
private final String folderDisposition = TEST_PREFIX + "RM-2937 folder ghosting";
private final String electronicRecord = "RM-2937 electronic 2 record";
private final String nonElectronicRecord = "RM-2937 non-electronic record";
@BeforeClass(alwaysRun = true)
private void setUp(){
STEP("Create the RM site if doesn't exist");
createRMSiteIfNotExists();
STEP("Create record category");
Category1 = createRootCategory(getRandomName("Title"));
}
@Test
@AlfrescoTest(jira="RM-2937")
public void foldersDispositionScheduleWithoutGhosting() {
//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.addDestroyWithoutGhostingAfterPeriodStep(Category1.getName(), "day|1", CUT_OFF_DATE);
//create folders
RecordCategoryChild FOLDER_DESTROY = createFolder(getAdminUser(),Category1.getId(),folderDisposition);
Record elRecord = createElectronicRecord(FOLDER_DESTROY.getId(),electronicRecord);
Record nonElRecord = createNonElectronicRecord(FOLDER_DESTROY.getId(),nonElectronicRecord);
// complete records
completeRecord(elRecord.getId());
completeRecord(nonElRecord.getId());
// 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());
// edit disposition date
recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),FOLDER_DESTROY.getName());
Utility.waitToLoopTime(5,"Waiting for Edit Disposition to be processed");
// Destroy the FOLDER_DESTROY
recordFoldersAPI.postFolderAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","destroy"),FOLDER_DESTROY.getName());
}
@AfterMethod(alwaysRun = true)
private void deletePreconditions() {
deleteRecordCategory(Category1.getId());
}
}

View File

@@ -0,0 +1,202 @@
/*
* #%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.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.RecordFoldersAPI;
import org.alfresco.rest.v0.RecordsAPI;
import org.alfresco.rest.v0.service.DispositionScheduleService;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.Utility;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
import java.io.IOException;
import java.time.Instant;
import static org.alfresco.rest.rm.community.base.TestData.DEFAULT_PASSWORD;
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.utility.report.log.Step.STEP;
/**
* Contains recordsDispositionScheduleWithoutGhosting test which checks disposition schedule cut off, transfer and destroy without maintaining metadata steps applied to records
* <p/>
* Precondition:
* <p/>
* RM site created, contains an empty category "RM-2801 disposition for records". <p/>
* RM user has RM admin role. <p/>
* A transfer location named "transferred files" is created to which RM user has access
* <p/>
* <img src="doc-files/Disposition Schedule without ghosting.png" alt="Records Disposition Schedule without ghosting" />
*
* @author Kavit Shah
*/
public class RecordsDispositionScheduleTests extends BaseRMRestTest {
/** data prep 6services */
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired
private RecordsAPI recordsAPI;
@Autowired
private RecordFoldersAPI recordFoldersAPI;
@Autowired
private DispositionScheduleService dispositionScheduleService;
private RecordCategory Category1;
private final String TEST_PREFIX = generateTestPrefix(RecordsDispositionScheduleTests.class);
private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
private final String recordsCategory = TEST_PREFIX + "RM-2801 category";
private final String folderDisposition = TEST_PREFIX + "RM-2801 folder";
@Test
@AlfrescoTest(jira="RM-2801")
public void recordsDispositionScheduleWithoutGhosting() {
// create test precondition
createTestPrecondition(recordsCategory);
// create disposition schedule
dispositionScheduleService.createCategoryRetentionSchedule(Category1.getName(), true);
// add cut off step
dispositionScheduleService.addCutOffImmediatelyStep(Category1.getName());
// add transfer step
dispositionScheduleService.addTransferAfterEventStep(Category1.getName(),"transferred records","all_allowances_granted_are_terminated");
// add destroy step without retaining metadata
dispositionScheduleService.addDestroyWithoutGhostingAfterPeriodStep(Category1.getName(), "day|1", CUT_OFF_DATE);
// create a folder and an electronic and a non-electronic record in it
RecordCategoryChild FOLDER_DESTROY = createFolder(getAdminUser(),Category1.getId(),folderDisposition);
String electronicRecord = "RM-2801 electronic record";
Record elRecord = createElectronicRecord(FOLDER_DESTROY.getId(), electronicRecord);
String nonElectronicRecord = "RM-2801 non-electronic record";
Record nonElRecord = createNonElectronicRecord(FOLDER_DESTROY.getId(), nonElectronicRecord);
// complete records and cut them off
String nonElRecordName = recordsAPI.getRecordFullName(getAdminUser().getUsername(),
getAdminUser().getPassword(), folderDisposition, nonElectronicRecord);
String elRecordName = recordsAPI.getRecordFullName(getAdminUser().getUsername(),
getAdminUser().getPassword(), folderDisposition, electronicRecord);
// complete records and cut them off
completeRecord(elRecord.getId());
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);
String elRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordName, "/" + Category1.getName() + "/" + folderDisposition);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),elRecordNameNodeRef);
// ensure the complete event action is displayed for both events
rmRolesAndActionsAPI.completeEvent(getAdminUser().getUsername(),
getAdminUser().getPassword(), nonElRecordName, RMEvents.ALL_ALLOWANCES_GRANTED_ARE_TERMINATED, Instant.now());
rmRolesAndActionsAPI.completeEvent(getAdminUser().getUsername(),
getAdminUser().getPassword(), elRecordName, RMEvents.ALL_ALLOWANCES_GRANTED_ARE_TERMINATED, Instant.now());
// Create and Complete transfer
HttpResponse nonElRecordNameHttpResponse = recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","transfer"),recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), nonElRecordName, "/" + Category1.getName() + "/" + folderDisposition));
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(), elRecordName, "/" + Category1.getName() + "/" + folderDisposition));
String elRecordNameTransferId = getTransferId(elRecordNameHttpResponse,elRecordNameNodeRef);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","transferComplete"),elRecordNameTransferId);
// edit the disposition schedule date to current date
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),nonElRecordNameNodeRef);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),elRecordNameNodeRef);
Utility.waitToLoopTime(5,"Waiting for Edit Disposition to be processed");
// destroy 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);
// 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 two category");
Category1 = createRootCategory(categoryName,"Title");
}
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();
}
}

View File

@@ -0,0 +1,200 @@
/*
* #%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.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.RecordFoldersAPI;
import org.alfresco.rest.v0.RecordsAPI;
import org.alfresco.rest.v0.service.DispositionScheduleService;
import org.alfresco.test.AlfrescoTest;
import org.alfresco.utility.Utility;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
import java.io.IOException;
import java.time.Instant;
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;
/**
* Contains recordsDispositionScheduleWithGhosting test which checks disposition schedule cut off, transfer and destroy with maintaining record metadata steps applied to records
* <p/>
* Precondition:
* <p/>
* RM site created, contains an empty category "RM-2937 disposition for records with ghosting". <p/>
* RM user has RM admin role. <p/>
* A transfer location named "transferred files with ghosting" is created to which RM user has access
* <p/>
* <img src="doc-files/Disposition Schedule with ghosting.png" alt="Records Disposition Schedule with ghosting" />
*
* @author Kavit Shah
*/
public class RecordsDispositionScheduleWithGhostingTests extends BaseRMRestTest {
/** data prep 6services */
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@Autowired
private RecordsAPI recordsAPI;
@Autowired
private RecordFoldersAPI recordFoldersAPI;
@Autowired
private DispositionScheduleService dispositionScheduleService;
private RecordCategory Category1;
private final String TEST_PREFIX = generateTestPrefix(RecordsDispositionScheduleTests.class);
private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
private final String recordsCategory = TEST_PREFIX + "RM-2801 category";
private final String folderDisposition = TEST_PREFIX + "RM-2801 folder";
@Test
@AlfrescoTest(jira="RM-2801")
public void recordsDispositionScheduleWithGhosting() {
// create test precondition
createTestPrecondition(recordsCategory);
// create disposition schedule
dispositionScheduleService.createCategoryRetentionSchedule(Category1.getName(), true);
// add cut off step
dispositionScheduleService.addCutOffImmediatelyStep(Category1.getName());
// add transfer step
dispositionScheduleService.addTransferAfterEventStep(Category1.getName(),"transferred records","all_allowances_granted_are_terminated");
// add destroy step without retaining metadata
dispositionScheduleService.addDestroyWithGhostingImmediatelyAfterCutOff(Category1.getName());
// create a folder and an electronic and a non-electronic record in it
RecordCategoryChild FOLDER_DESTROY = createFolder(getAdminUser(),Category1.getId(),folderDisposition);
String electronicRecord = "RM-2801 electronic record";
Record elRecord = createElectronicRecord(FOLDER_DESTROY.getId(), electronicRecord);
String nonElectronicRecord = "RM-2801 non-electronic record";
Record nonElRecord = createNonElectronicRecord(FOLDER_DESTROY.getId(), nonElectronicRecord);
// complete records and cut them off
String nonElRecordName = recordsAPI.getRecordFullName(getAdminUser().getUsername(),
getAdminUser().getPassword(), folderDisposition, nonElectronicRecord);
String elRecordName = recordsAPI.getRecordFullName(getAdminUser().getUsername(),
getAdminUser().getPassword(), folderDisposition, electronicRecord);
// complete records and cut them off
completeRecord(elRecord.getId());
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);
String elRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordName, "/" + Category1.getName() + "/" + folderDisposition);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","cutoff"),elRecordNameNodeRef);
// ensure the complete event action is displayed for both events
rmRolesAndActionsAPI.completeEvent(getAdminUser().getUsername(),
getAdminUser().getPassword(), nonElRecordName, RMEvents.ALL_ALLOWANCES_GRANTED_ARE_TERMINATED, Instant.now());
rmRolesAndActionsAPI.completeEvent(getAdminUser().getUsername(),
getAdminUser().getPassword(), elRecordName, RMEvents.ALL_ALLOWANCES_GRANTED_ARE_TERMINATED, Instant.now());
// Create and Complete transfer
HttpResponse nonElRecordNameHttpResponse = recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","transfer"),recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), nonElRecordName, "/" + Category1.getName() + "/" + folderDisposition));
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(), elRecordName, "/" + Category1.getName() + "/" + folderDisposition));
String elRecordNameTransferId = getTransferId(elRecordNameHttpResponse,elRecordNameNodeRef);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),new JSONObject().put("name","transferComplete"),elRecordNameTransferId);
// edit the disposition schedule date to current date
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),nonElRecordNameNodeRef);
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),
getAdminUser().getPassword(),editDispositionDateJson(),elRecordNameNodeRef);
Utility.waitToLoopTime(5,"Waiting for Edit Disposition to be processed");
// destroy 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);
// 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 two category");
Category1 = createRootCategory(categoryName,"Title");
}
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();
}
}

View File

@@ -0,0 +1,124 @@
/*
* #%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.record.RecordContent;
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.UnfiledContainerChild;
import org.alfresco.rest.rm.community.model.unfiledcontainer.UnfiledContainerChildProperties;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.RulesAPI;
import org.alfresco.test.AlfrescoTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.alfresco.rest.core.v0.BaseAPI.NODE_PREFIX;
import static org.alfresco.rest.rm.community.base.TestData.ELECTRONIC_RECORD_NAME;
import static org.alfresco.rest.rm.community.base.TestData.NONELECTRONIC_RECORD_NAME;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.*;
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.http.HttpStatus.*;
public class UnfiledRecordsRuleTests extends BaseRMRestTest {
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
private final String TEST_PREFIX = generateTestPrefix(CreateCategoriesTests.class);
private final String RM_ADMIN = TEST_PREFIX + "rm_admin";
private RecordCategory Category2;
private RecordCategoryChild Folder2;
@Autowired
private RulesAPI rulesAPI;
@Test
@AlfrescoTest(jira = "RM-2794")
public void unfiledRecordsRule() {
STEP("Create the RM site if doesn't exist");
createRMSiteIfNotExists();
STEP("Create RM Admin user");
rmRolesAndActionsAPI.createUserAndAssignToRole(getAdminUser().getUsername(), getAdminUser().getPassword(), RM_ADMIN,
getAdminUser().getPassword(),
"Administrator");
STEP("Create record categories and record folders");
Category2 = createRootCategory(getRandomName("recordCategory"));
Folder2 = createFolder(Category2.getId(), getRandomName("recordFolder"));
STEP("Get the unfiled records container");
UnfiledContainer container = getRestAPIFactory().getUnfiledContainersAPI().getUnfiledContainer(UNFILED_RECORDS_CONTAINER_ALIAS);
// Check the response code
assertStatusCode(OK);
//create a rule
RuleDefinition ruleDefinition = RuleDefinition.createNewRule().title("name").description("description")
.applyToChildren(true)
.actions(Collections.singletonList(ActionsOnRule.FILE_TO.getActionValue()));
rulesAPI.createRule(getAdminUser().getUsername(), getAdminUser().getPassword(), NODE_PREFIX + container.getId(), ruleDefinition);
//upload an electronic record
UnfiledContainerChild electronicRecord = UnfiledContainerChild.builder()
.name(ELECTRONIC_RECORD_NAME)
.nodeType(CONTENT_TYPE)
.content(RecordContent.builder().mimeType("text/plain").build())
.build();
assertStatusCode(OK);
// create a non-electronic record
UnfiledContainerChild nonelectronicRecord = UnfiledContainerChild.builder()
.properties(UnfiledContainerChildProperties.builder()
.description(NONELECTRONIC_RECORD_NAME)
.title("Title")
.build())
.name(NONELECTRONIC_RECORD_NAME)
.nodeType(NON_ELECTRONIC_RECORD_TYPE)
.build();
assertStatusCode(OK);
//delete the record created, delete the rule from UnfilledRecord page, delete the category created
rulesAPI.deleteAllRulesOnContainer(getAdminUser().getUsername(), getAdminUser().getPassword(), NODE_PREFIX + container.getId());
deleteRecordCategory(Category2.getId());
assertStatusCode(NO_CONTENT);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

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.
@@ -40,6 +40,7 @@ import org.json.JSONObject;
import org.junit.Assert;
import org.springframework.extensions.webscripts.TestWebScriptServer;
import org.springframework.extensions.webscripts.TestWebScriptServer.GetRequest;
import org.springframework.extensions.webscripts.TestWebScriptServer.Response;
import java.io.Serializable;
import java.util.ArrayList;
@@ -194,13 +195,13 @@ public class SlingshotContentGetTest extends BaseWebScriptTest
NodeRef rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER);
NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content");
NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN);
NodeRef folderX = createNode(rootFolder, "X", ContentModel.TYPE_FOLDER);
NodeRef folderY = createNode(folderX, "Y", ContentModel.TYPE_FOLDER);
NodeRef folderZ = createNode(folderY, "Z", ContentModel.TYPE_FOLDER);
NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content");
NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN);
// uri with relative path at the end
String uri = URL_CONTENT_DOWNLOAD + doc1.getId() + "/X/Y/Z/doc2";
@@ -212,7 +213,50 @@ public class SlingshotContentGetTest extends BaseWebScriptTest
nodeService.deleteNode(rootFolder);
}
public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content)
public void testForcedAttachment() throws Exception
{
Repository repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper");
NodeRef companyHome = repositoryHelper.getCompanyHome();
NodeRef rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER);
NodeRef testhtml = createNodeWithTextContent(rootFolder, "testhtml", ContentModel.TYPE_CONTENT, "testhtml content", MimetypeMap.MIMETYPE_HTML);
NodeRef testpdf = createNodeWithTextContent(rootFolder, "testpdf", ContentModel.TYPE_CONTENT, "testpdf content", MimetypeMap.MIMETYPE_PDF);
String uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=false";
GetRequest req = new GetRequest(uri);
Response res = sendRequest(req, 200);
assertEquals("attachment", res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
uri = URL_CONTENT_DOWNLOAD + testhtml.getId();
res = sendRequest(new GetRequest(uri), 200);
assertEquals("attachment", res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=true";
res = sendRequest(new GetRequest(uri), 200);
assertEquals("attachment", res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=false";
res = sendRequest(new GetRequest(uri), 200);
assertNull(res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
uri = URL_CONTENT_DOWNLOAD + testpdf.getId();
res = sendRequest(new GetRequest(uri), 200);
assertNull(res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=true";
res = sendRequest(new GetRequest(uri), 200);
assertEquals("attachment", res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
nodeService.deleteNode(rootFolder);
}
public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content, String mimetype)
{
NodeRef nodeRef = createNode(parentNode, nodeCmName, nodeType);
@@ -220,7 +264,7 @@ public class SlingshotContentGetTest extends BaseWebScriptTest
if (content != null)
{
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.setMimetype(mimetype);
writer.setEncoding("UTF-8");
writer.putContent(content);
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
# Fetch image based on Tomcat 9.0, Java 11 and Centos 7
# 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-jre11-centos7-202203091924
FROM alfresco/alfresco-base-tomcat:tomcat9-jre17-rockylinux8-202205140719
# Set default docker_context.
ARG resource_path=target
@@ -65,12 +65,12 @@ RUN sed -i -e "s_log4j.appender.File.File\=alfresco.log_log4j.appender.File.File
# fontconfig is required by Activiti worflow diagram generator
# installing pinned dependencies as well
RUN yum install -y fontconfig-2.13.0-4.3.el7 \
dejavu-fonts-common-2.33-6.el7 \
fontpackages-filesystem-1.44-8.el7 \
freetype-2.8-14.el7_9.1 \
libpng-1.5.13-8.el7 \
dejavu-sans-fonts-2.33-6.el7 && \
RUN yum install -y fontconfig-2.13.1-4.el8 \
dejavu-fonts-common-2.35-7.el8 \
fontpackages-filesystem-1.44-22.el8 \
freetype-2.9.1-4.el8_3.1 \
libpng-1.6.34-5.el8 \
dejavu-sans-fonts-2.35-7.el8 && \
yum clean all
# The standard configuration is to have all Tomcat files owned by root with group GROUPNAME and whilst owner has read/write privileges,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>17.56</version>
<version>17.102-SNAPSHOT</version>
</parent>
<developers>
@@ -106,8 +106,10 @@
<suiteXmlFiles>
<suiteXmlFile>${suiteXmlFile}</suiteXmlFile>
</suiteXmlFiles>
<!-- Keeping illegal-access=warn for Java 11 compatibility, even though it has no effect on JDK 17 -->
<argLine>
--illegal-access=warn
--add-opens=java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</plugin>

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>17.56</version>
<version>17.102-SNAPSHOT</version>
</parent>
<developers>
@@ -78,8 +78,10 @@
<suiteXmlFiles>
<suiteXmlFile>${suiteXmlFile}</suiteXmlFile>
</suiteXmlFiles>
<!-- Keeping illegal-access=warn for Java 11 compatibility, even though it has no effect on JDK 17 -->
<argLine>
--illegal-access=warn
--add-opens=java.base/java.lang=ALL-UNNAMED
</argLine>
</configuration>
</plugin>

View File

@@ -27,7 +27,11 @@ package org.alfresco.rest.rules;
import static java.util.stream.Collectors.toList;
import static org.alfresco.rest.rules.RulesTestsUtils.*;
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
import static org.alfresco.utility.constants.UserRole.SiteConsumer;
import static org.alfresco.utility.constants.UserRole.SiteContributor;
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;
@@ -37,12 +41,17 @@ import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.rest.model.RestRuleModelsCollection;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
@@ -57,6 +66,8 @@ import org.testng.annotations.Test;
@Test(groups = {TestGroup.RULES})
public class CreateRulesTests extends RestTest
{
private static final String IGNORE_ID = "id";
private static final String IGNORE_IS_SHARED = "isShared";
private UserModel user;
private SiteModel site;
private FolderModel ruleFolder;
@@ -69,20 +80,26 @@ 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 = new RestRuleModel();
ruleModel.setName("ruleName");
RestRuleModel ruleModel = createRuleModelWithModifiedValues();
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = createRuleModelWithModifiedValues();
expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
expectedRuleModel.setConditions(createEmptyConditionModel());
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().field("id").isNotNull()
.assertThat().field("name").is("ruleName");
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
.assertThat().field("id").isNotNull()
.assertThat().field("isShared").isNull();
}
/** Check creating a rule in a non-existent folder returns an error. */
@@ -120,8 +137,7 @@ public class CreateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void createRuleWithEmptyName()
{
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName("");
RestRuleModel ruleModel = createRuleModel("");
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
@@ -133,8 +149,7 @@ public class CreateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void duplicateRuleNameIsAcceptable()
{
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName("duplicateRuleName");
RestRuleModel ruleModel = createRuleModel("duplicateRuleName");
STEP("Create two identical rules");
RestRuleModel ruleA = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
@@ -163,26 +178,42 @@ public class CreateRulesTests extends RestTest
restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
}
/** Check that a user without write permission for the folder cannot create a rule in it. */
public void requireWritePermissionToCreateRule()
/** Check that a Collaborator cannot create a rule in a private folder. */
public void siteCollaboratorCannotCreateRule()
{
STEP("Create a user and use them to create a private site containing a folder");
UserModel privateUser = dataUser.createRandomTestUser();
SiteModel privateSite = dataSite.usingUser(privateUser).createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingUser(privateUser).usingSite(privateSite).createFolder();
STEP("Create a collaborator and check they cannot create a rule in the private folder");
UserModel collaborator = dataUser.createRandomTestUser();
dataUser.addUserToSite(collaborator, privateSite, SiteCollaborator);
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName("ruleName");
restClient.authenticateUser(collaborator).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
testRolePermissionsWith(SiteCollaborator);
restClient.assertStatusCodeIs(FORBIDDEN);
restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
}
/** Check that a Contributor cannot create a rule in a private folder. */
public void siteContributorCannotCreateRule()
{
testRolePermissionsWith(SiteContributor);
restClient.assertStatusCodeIs(FORBIDDEN);
restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
}
/** Check that a Consumer cannot create a rule in a private folder. */
public void siteConsumerCannotCreateRule()
{
testRolePermissionsWith(SiteConsumer);
restClient.assertStatusCodeIs(FORBIDDEN);
restClient.assertLastError().containsSummary("Insufficient permissions to manage rules");
}
/** Check that a siteManager can create a rule in a private folder. */
public void siteManagerCanCreateRule()
{
testRolePermissionsWith(SiteManager)
.assertThat().field("id").isNotNull()
.assertThat().field("name").is("testRule");
restClient.assertStatusCodeIs(CREATED);
}
/** Check we can't create a rule under a document node. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void tryToCreateRuleUnderDocument()
@@ -205,12 +236,7 @@ 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(ruleName ->
{
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName(ruleName);
return ruleModel;
}).collect(toList());
List<RestRuleModel> ruleModels = ruleNames.stream().map(RulesTestsUtils::createRuleModel).collect(toList());
RestRuleModelsCollection rules = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createListOfRules(ruleModels);
@@ -229,12 +255,10 @@ public class CreateRulesTests extends RestTest
public void createRulesWithOneError()
{
STEP("Try to create a three rules but the middle one has an error.");
RestRuleModel ruleA = new RestRuleModel();
ruleA.setName("ruleA");
RestRuleModel ruleB = new RestRuleModel();
RestRuleModel ruleA = createRuleModel("ruleA");
RestRuleModel ruleB = createRuleModel("");
// Don't set a name for Rule B.
RestRuleModel ruleC = new RestRuleModel();
ruleC.setName("ruleC");
RestRuleModel ruleC = createRuleModel("ruleC");
List<RestRuleModel> ruleModels = List.of(ruleA, ruleB, ruleC);
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createListOfRules(ruleModels);
@@ -242,4 +266,130 @@ public class CreateRulesTests extends RestTest
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 = createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().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 = createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().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 = createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().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 = createRuleModelWithDefaultValues();
ruleModel.setIsShared(true);
UserModel admin = dataUser.getAdminUser();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().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 = createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().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");
SiteModel privateSite = dataSite.usingUser(user).createPrivateRandomSite();
FolderModel privateFolder = dataContent.usingUser(user).usingSite(privateSite).createFolder();
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(createDefaultActionModel()));
return restClient.authenticateUser(userWithRole).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
}
/**
* Check we can create a rule with several actions.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void createRuleWithActions()
{
final Map<String, Serializable> copyParams =
Map.of("destination-folder", "dummy-folder-node", "deep-copy", true);
final RestActionBodyExecTemplateModel copyAction = createCustomActionModel("copy", copyParams);
final Map<String, Serializable> checkOutParams =
Map.of("destination-folder", "dummy-folder-node", "assoc-name", "cm:checkout", "assoc-type",
"cm:contains");
final RestActionBodyExecTemplateModel checkOutAction = createCustomActionModel("check-out", checkOutParams);
final Map<String, Serializable> scriptParams = Map.of("script-ref", "dummy-script-node-id");
final RestActionBodyExecTemplateModel scriptAction = createCustomActionModel("script", scriptParams);
final RestRuleModel ruleModel = createRuleModelWithDefaultValues();
ruleModel.setActions(Arrays.asList(copyAction, checkOutAction, scriptAction));
final UserModel admin = dataUser.getAdminUser();
final RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
final RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
expectedRuleModel.setActions(addActionContextParams(Arrays.asList(copyAction, checkOutAction, scriptAction)));
expectedRuleModel.setConditions(createEmptyConditionModel());
expectedRuleModel.setTriggers(List.of("inbound"));
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
.assertThat().field("isShared").isNull();
}
}

View File

@@ -0,0 +1,254 @@
/*
* #%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.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;
import static org.alfresco.utility.report.log.Step.STEP;
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 java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.rest.model.RestRuleModelsCollection;
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.junit.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Tests for DELETE /nodes/{nodeId}/rule-sets/{ruleSetId}/rules/{ruleId}.
*/
@Test(groups = {TestGroup.RULES})
public class DeleteRulesTests extends RestTest
{
private static final String FAKE_NODE_REF = "fake-node-id";
private UserModel user;
private SiteModel site;
@BeforeClass(alwaysRun = true)
public void dataPreparation()
{
STEP("Create a Contributor user and a public site");
user = dataUser.createRandomTestUser();
user.setUserRole(SiteContributor);
site = dataSite.usingUser(user).createPublicRandomSite();
}
/**
* Delete previously created rule by its id (as Contributor).
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY})
public void deleteSingleRuleAndGet204()
{
STEP("Create a few rules in the folder");
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()
.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.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.assertStatusCodeIs(OK);
rulesAfterDeletion.assertThat().entriesListCountIs(createdRules.size() - 1);
Assert.assertTrue(rulesAfterDeletion.getEntries()
.stream()
.noneMatch(r -> r.onModel().getId().equals(ruleA.getId()))
);
final Set<String> ruleIdsThatShouldBeLeft = createdRules.stream()
.filter(r -> !r.getName().equals("ruleA"))
.map(RestRuleModel::getId)
.collect(Collectors.toSet());
final Set<String> ruleIdsAfterDeletion = rulesAfterDeletion.getEntries().stream()
.map(r -> r.onModel().getId())
.collect(Collectors.toSet());
Assert.assertEquals(ruleIdsThatShouldBeLeft, ruleIdsAfterDeletion);
}
/**
* Try to delete a rule in a non-existing folder and get 404.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void deleteRuleInNonExistingFolderAndGet404()
{
final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
final RestRuleModel testRule = createRule(ruleFolder);
STEP("Create a non-existing folder model");
final FolderModel nonExistingFolder = new FolderModel();
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.assertLastError().statusCodeIs(NOT_FOUND);
}
/**
* Try to delete a rule in a non-existing rule set and get 404.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void deleteRuleInNonExistingRuleSetAndGet404()
{
final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
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.assertLastError().statusCodeIs(NOT_FOUND);
}
/**
* Try to delete a non-existing rule and get 404.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY})
public void deleteNonExistingRuleAndGet404()
{
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.assertLastError().statusCodeIs(NOT_FOUND);
}
/**
* Try to delete an existing rule passing a wrong but existing folder and get 404.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY})
public void deleteExistingRuleFromWrongFolderAndGet404()
{
final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
final RestRuleModel testRule = createRule(ruleFolder);
STEP("Create a second folder in the site");
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.assertLastError().statusCodeIs(NOT_FOUND);
}
/**
* Check that a user without write permission on folder cannot delete a rule inside it.
*/
public void deleteSinglePrivateRuleWithoutPermissionAndGet403()
{
STEP("Create a user and use them to create a private site containing a folder with a rule");
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 createdRule =
restClient.authenticateUser(privateUser).withCoreAPI().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.assertLastError().statusCodeIs(FORBIDDEN);
}
/**
* Check that a user with SiteCollaborator permissions on folder can delete a rule inside it.
*/
public void deleteSinglePublicRuleAsCollaboratorAndGet403()
{
STEP("Create a user and use them to create a private site containing a folder with a rule");
final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
final RestRuleModel testRule = createRule(ruleFolder);
STEP("Create a manager in the private site");
final UserModel siteCollaborator = dataUser.createRandomTestUser();
siteCollaborator.setUserRole(SiteCollaborator);
restClient.authenticateUser(user).withCoreAPI().usingSite(site).addPerson(siteCollaborator);
STEP("Check the manager can delete the rule");
restClient.authenticateUser(siteCollaborator).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.deleteRule(testRule.getId());
restClient.assertLastError().statusCodeIs(FORBIDDEN);
}
/**
* Check that a user with SiteManager permissions on folder can delete a rule inside it.
*/
public void deleteSinglePrivateRuleAsSiteManagerAndGet204()
{
STEP("Create a user and use them to create a private site containing a folder with a rule");
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 createdRule =
restClient.authenticateUser(privateUser).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Create a manager in the private site");
final UserModel siteManager = dataUser.createRandomTestUser();
siteManager.setUserRole(SiteManager);
restClient.authenticateUser(privateUser).withCoreAPI().usingSite(privateSite).addPerson(siteManager);
STEP("Check the manager can delete the rule");
restClient.authenticateUser(siteManager).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet()
.deleteRule(createdRule.getId());
restClient.assertStatusCodeIs(NO_CONTENT);
}
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);
}
}

View File

@@ -0,0 +1,210 @@
/*
* #%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.createRuleModel;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.junit.Assert.assertTrue;
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.RestRuleModel;
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 and /nodes/{nodeId}/rule-sets/{ruleSetId}.
*/
@Test (groups = { TestGroup.RULES })
public class GetRuleSetsTests extends RestTest
{
private UserModel user;
private SiteModel site;
private FolderModel ruleFolder;
private RestRuleModel rule;
private String ruleSetId;
@BeforeClass (alwaysRun = true)
public void dataPreparation()
{
STEP("Create a user, site and folder.");
user = dataUser.createRandomTestUser();
site = dataSite.usingUser(user).createPublicRandomSite();
ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Create a rule in the folder.");
RestRuleModel ruleModel = createRuleModel("ruleName");
rule = restClient.authenticateUser(user).withCoreAPI().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)
.getListOfRuleSets();
ruleSets.assertThat().entriesListCountIs(1);
ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
}
/** Check we can get an empty list of rule sets. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getEmptyRuleSetsList()
{
STEP("Create a folder in existing site");
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Get the rule sets for the folder");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI()
.usingNode(folder).getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
assertTrue("Expected no rule sets to be present.", ruleSets.isEmpty());
}
/** Check we can get a list of rule sets. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getRuleSetsList()
{
STEP("Get the rule sets for the folder");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
.getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
ruleSets.assertThat().entriesListCountIs(1);
ruleSets.getEntries().get(0).onModel()
.assertThat().field("id").isNotNull();
}
/** Check we get a 404 if trying to load rule sets for a folder that doesn't exist. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getRuleSetsForNonExistentFolder()
{
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.assertStatusCodeIs(NOT_FOUND);
}
/** 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()
.usingNode(ruleFolder)
.include("owningFolder")
.getListOfRuleSets();
restClient.assertStatusCodeIs(OK);
ruleSets.getEntries().get(0).onModel()
.assertThat().field("owningFolder").is(ruleFolder.getNodeRef())
.assertThat().field("id").is(ruleSetId);
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 getRuleSetsAndInclusionType()
{
STEP("Get the rule sets and inclusion type");
RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI()
.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 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)
.getRuleSet(ruleSetId);
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("id").is(ruleSetId);
}
/** Check we can get a rule set using the "-default-" synonym. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getDefaultRuleSetById()
{
STEP("Get the default rule set for the folder");
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
.getDefaultRuleSet();
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("id").isNotNull();
}
/** Check we get a 404 if trying to load the default rule set for a folder that doesn't exist. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getDefaultRuleSetForNonExistentFolder()
{
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.assertStatusCodeIs(NOT_FOUND);
}
/** Check we get 404 for a non-existing rule set id. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getRuleSetByNonExistingId()
{
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.assertStatusCodeIs(NOT_FOUND);
}
/** Check we can get the id of the folder that owns a rule set. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getRuleSetAndOwningFolder()
{
STEP("Get the rule set and owning folder");
RestRuleSetModel ruleSet = restClient.authenticateUser(user).withCoreAPI()
.usingNode(ruleFolder)
.include("owningFolder")
.getRuleSet(ruleSetId);
restClient.assertStatusCodeIs(OK);
ruleSet.assertThat().field("owningFolder").is(ruleFolder.getNodeRef())
.assertThat().field("id").is(ruleSetId);
}
}

View File

@@ -27,12 +27,14 @@ package org.alfresco.rest.rules;
import static java.util.stream.Collectors.toList;
import static org.alfresco.rest.rules.RulesTestsUtils.*;
import static org.alfresco.utility.constants.UserRole.SiteCollaborator;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.junit.Assert.assertTrue;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.OK;
import static org.springframework.http.HttpStatus.CREATED;
import java.util.List;
import java.util.stream.IntStream;
@@ -59,6 +61,8 @@ public class GetRulesTests extends RestTest
private FolderModel ruleFolder;
private List<RestRuleModel> createdRules;
private RestRuleModel createdRuleA;
private static final String IGNORE_ID = "id";
private static final String IGNORE_IS_SHARED = "isShared";
@BeforeClass(alwaysRun = true)
public void dataPreparation()
@@ -70,8 +74,7 @@ public class GetRulesTests extends RestTest
STEP("Create rules in the folder");
createdRules = Stream.of("ruleA", "ruleB").map(ruleName -> {
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName(ruleName);
RestRuleModel ruleModel = createRuleModel(ruleName);
return restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
}).collect(toList());
createdRuleA = createdRules.get(0);
@@ -87,11 +90,15 @@ public class GetRulesTests extends RestTest
STEP("Get the rules that apply to the folder");
RestRuleModelsCollection rules = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).usingDefaultRuleSet().getListOfRules();
restClient.assertStatusCodeIs(OK);
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()
{
@@ -102,8 +109,9 @@ public class GetRulesTests extends RestTest
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. */
@@ -128,7 +136,33 @@ public class GetRulesTests extends RestTest
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).withCoreAPI().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("enabled").is(false)
.assertThat().field("cascade").is(false)
.assertThat().field("asynchronous").is(false)
.assertThat().field("errorScript").isNull()
.assertThat().field("shared").isNull()
.assertThat().field("triggers").is("[inbound]"));
}
/**
* 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()
{
@@ -138,7 +172,56 @@ public class GetRulesTests extends RestTest
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 = createRuleModelWithModifiedValues();
ruleModel.setTriggers(List.of("update"));
UserModel admin = dataUser.getAdminUser();
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(folder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = createRuleModelWithModifiedValues();
expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
expectedRuleModel.setTriggers(List.of("update"));
expectedRuleModel.setConditions(createEmptyConditionModel());
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
.assertThat().field("id").isNotNull()
.assertThat().field("isShared").isNull();
}
/** Check we can get rule's "other" fields */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
public void getRulesDefaultFields()
{
STEP("Create a rule with all other fields default values");
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
UserModel admin = dataUser.getAdminUser();
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
RestRuleModel rule = restClient.authenticateUser(admin).withCoreAPI().usingNode(folder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
RestRuleModel expectedRuleModel = createRuleModelWithDefaultValues();
expectedRuleModel.setActions(addActionContextParams(expectedRuleModel.getActions()));
expectedRuleModel.setTriggers(List.of("inbound"));
expectedRuleModel.setConditions(createEmptyConditionModel());
restClient.assertStatusCodeIs(CREATED);
restClient.assertStatusCodeIs(CREATED);
rule.assertThat().isEqualTo(expectedRuleModel, IGNORE_ID, IGNORE_IS_SHARED)
.assertThat().field("id").isNotNull()
.assertThat().field("isShared").isNull();
}
/** Check we get a 404 if trying to load a rule from a folder that doesn't exist. */
@@ -163,6 +246,29 @@ public class GetRulesTests extends RestTest
restClient.assertStatusCodeIs(NOT_FOUND);
}
/** Check we get a 404 if trying to load an existing rule providing a wrong but existing folder */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void getSingleRuleFromWrongFolder()
{
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.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).withCoreAPI().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()
{
@@ -189,8 +295,7 @@ 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 = new RestRuleModel();
ruleModel.setName("Private site rule");
RestRuleModel ruleModel = createRuleModel("Private site rule");
restClient.authenticateUser(privateUser).withCoreAPI().usingNode(privateFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
STEP("Create a collaborator in the private site");

View File

@@ -0,0 +1,313 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.rules;
import static org.alfresco.rest.rules.RulesTestsUtils.createRuleModel;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestRuleModel;
import org.alfresco.rest.model.RestRuleModelsCollection;
import org.alfresco.rest.model.RestRuleSetLinkModel;
import org.alfresco.rest.model.RestRuleSetModel;
import org.alfresco.rest.model.RestRuleSetModelsCollection;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.model.UserModel;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* Tests for /nodes/{nodeId}/rule-set-links.
*/
@Test(groups = {TestGroup.RULES})
public class RuleSetLinksTests extends RestTest
{
private UserModel user;
private SiteModel site;
@BeforeClass(alwaysRun = true)
public void dataPreparation()
{
STEP("Create a user and site.");
user = dataUser.createRandomTestUser();
site = dataSite.usingUser(user).createPublicRandomSite();
}
/**
* Check we can link to folder containing a rule set.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToFolderContainingRules()
{
STEP("Create folders in existing site");
final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Create a rule in the rule folder.");
RestRuleModel ruleModel = createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Get the rule sets for the folder and find the rule set id");
final RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
.getListOfRuleSets();
ruleSets.assertThat().entriesListCountIs(1);
final String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
STEP("Link to a rule folder");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(ruleFolder.getNodeRef());
final RestRuleSetLinkModel ruleLink = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
STEP("Assert link result");
restClient.assertStatusCodeIs(CREATED);
final RestRuleSetLinkModel expectedLink = new RestRuleSetLinkModel();
expectedLink.setId(ruleSetId);
ruleLink.assertThat().isEqualTo(expectedLink);
STEP("Check if folder returns same rules");
final RestRuleModelsCollection linkedRules = restClient.authenticateUser(user).withCoreAPI()
.usingNode(folder)
.usingDefaultRuleSet()
.getListOfRules();
linkedRules.assertThat().entriesListCountIs(1);
linkedRules.getEntries().get(0).onModel().assertThat().isEqualTo(rule);
STEP("Check if folder returns rule set with linked inclusionType");
final RestRuleSetModelsCollection linkedRuleSets = restClient.authenticateUser(user).withCoreAPI()
.usingNode(folder)
.include("inclusionType")
.getListOfRuleSets();
linkedRuleSets.assertThat().entriesListCountIs(1);
final RestRuleSetModel expectedRuleSet = new RestRuleSetModel();
expectedRuleSet.setId(ruleSetId);
expectedRuleSet.setInclusionType("linked");
linkedRuleSets.getEntries()
.get(0).onModel().assertThat().isEqualTo(expectedRuleSet);
}
/**
* Check we can link to a rule set.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToRuleSet()
{
STEP("Create folders in existing site");
final FolderModel ruleFolder = dataContent.usingUser(user).usingSite(site).createFolder();
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Create a rule in the rule folder.");
RestRuleModel ruleModel = createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Get the rule sets for the folder and find the rule set id");
final RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder)
.getListOfRuleSets();
ruleSets.assertThat().entriesListCountIs(1);
final String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
STEP("Link to a rule set");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(ruleSetId);
final RestRuleSetLinkModel ruleLink = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
STEP("Assert link result");
restClient.assertStatusCodeIs(CREATED);
final RestRuleSetLinkModel expectedLink = new RestRuleSetLinkModel();
expectedLink.setId(ruleSetId);
ruleLink.assertThat().isEqualTo(expectedLink);
STEP("Check if folder returns same rules");
final RestRuleModelsCollection linkedRules = restClient.authenticateUser(user).withCoreAPI()
.usingNode(folder)
.usingDefaultRuleSet()
.getListOfRules();
linkedRules.assertThat().entriesListCountIs(1);
linkedRules.getEntries().get(0).onModel().assertThat().isEqualTo(rule);
STEP("Check if folder returns rule set with linked inclusionType");
final RestRuleSetModelsCollection likedRuleSets = restClient.authenticateUser(user).withCoreAPI()
.usingNode(folder)
.include("inclusionType")
.getListOfRuleSets();
likedRuleSets.assertThat().entriesListCountIs(1);
final RestRuleSetModel expectedRuleSet = new RestRuleSetModel();
expectedRuleSet.setId(ruleSetId);
expectedRuleSet.setInclusionType("linked");
likedRuleSets.getEntries()
.get(0).onModel().assertThat().isEqualTo(expectedRuleSet);
}
/**
* Check we get 404 when linking to a non-existing rule set/folder.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToNonExistingRuleSet()
{
STEP("Create a folder in existing site");
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Link to non-existing rule set");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId("dummy-rule-set-id");
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
STEP("Assert link result is 404");
restClient.assertStatusCodeIs(NOT_FOUND);
}
/**
* Check we get bad request error when linking to a folder without rules.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToFolderWithoutRules()
{
STEP("Create 2 folders without rules in existing site");
final FolderModel folder1 = dataContent.usingUser(user).usingSite(site).createFolder();
final FolderModel folder2 = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Link to a folder without rules");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(folder2.getNodeRef());
restClient.authenticateUser(user).withCoreAPI().usingNode(folder1).createRuleLink(request);
STEP("Assert link result is 400");
restClient.assertStatusCodeIs(BAD_REQUEST)
.assertLastError().containsSummary("The target node has no rules to link.");
}
/**
* Check we get bad request error when linking from a folder which already has rules.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkFromFolderWithRules()
{
STEP("Create folders in existing site");
final FolderModel folder1 = dataContent.usingUser(user).usingSite(site).createFolder();
final FolderModel folder2 = dataContent.usingUser(user).usingSite(site).createFolder();
STEP("Create rules in both folders.");
RestRuleModel ruleModel1 = createRuleModel("ruleName1");
restClient.authenticateUser(user).withCoreAPI().usingNode(folder1).usingDefaultRuleSet()
.createSingleRule(ruleModel1);
RestRuleModel ruleModel2 = createRuleModel("ruleName2");
restClient.authenticateUser(user).withCoreAPI().usingNode(folder2).usingDefaultRuleSet()
.createSingleRule(ruleModel2);
STEP("Link from a folder with rules");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(folder2.getNodeRef());
restClient.authenticateUser(user).withCoreAPI().usingNode(folder1).createRuleLink(request);
STEP("Assert link result is 400");
restClient.assertStatusCodeIs(BAD_REQUEST)
.assertLastError().containsSummary(
"Unable to link to a ruleset because the folder has pre-existing rules or is already linked to a ruleset.");
}
/**
* Check we get bad request error when linking to a file node.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToFileNode()
{
STEP("Create a folder in existing site");
final FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
final FileModel fileContent = dataContent.usingUser(user).usingSite(site).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
STEP("Link to a file node");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(fileContent.getNodeRef());
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).createRuleLink(request);
STEP("Assert link result is 400");
restClient.assertStatusCodeIs(BAD_REQUEST)
.assertLastError().containsSummary("NodeId of a folder is expected!");
}
/**
* Check we can link to a parent folder with rules.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
public void linkToParentNodeWithRules()
{
STEP("Create parent/child folders in existing site");
final FolderModel parentFolder = dataContent.usingUser(user).usingSite(site).createFolder();
final FolderModel childFolder = dataContent.usingUser(user).usingSite(site).usingResource(parentFolder).createFolder();
STEP("Create a rule in the parent folder.");
RestRuleModel ruleModel = createRuleModel("ruleName");
RestRuleModel rule = restClient.authenticateUser(user).withCoreAPI().usingNode(parentFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
STEP("Get the rule sets for the folder and find the rule set id");
final RestRuleSetModelsCollection ruleSets = restClient.authenticateUser(user).withCoreAPI().usingNode(parentFolder)
.getListOfRuleSets();
ruleSets.assertThat().entriesListCountIs(1);
final String ruleSetId = ruleSets.getEntries().get(0).onModel().getId();
STEP("Link to the parent folder");
final RestRuleSetLinkModel request = new RestRuleSetLinkModel();
request.setId(parentFolder.getNodeRef());
final RestRuleSetLinkModel ruleLink = restClient.authenticateUser(user).withCoreAPI().usingNode(childFolder).createRuleLink(request);
STEP("Assert link result");
restClient.assertStatusCodeIs(CREATED);
final RestRuleSetLinkModel expectedLink = new RestRuleSetLinkModel();
expectedLink.setId(ruleSetId);
ruleLink.assertThat().isEqualTo(expectedLink);
STEP("Check if child folder returns same rules");
final RestRuleModelsCollection linkedRules = restClient.authenticateUser(user).withCoreAPI()
.usingNode(childFolder)
.usingDefaultRuleSet()
.getListOfRules();
linkedRules.assertThat().entriesListCountIs(1);
linkedRules.getEntries().get(0).onModel().assertThat().isEqualTo(rule);
STEP("Check if child folder returns rule set with linked inclusionType");
final RestRuleSetModelsCollection linkedRuleSets = restClient.authenticateUser(user).withCoreAPI()
.usingNode(childFolder)
.include("inclusionType")
.getListOfRuleSets();
linkedRuleSets.assertThat().entriesListCountIs(1);
final RestRuleSetModel expectedRuleSet = new RestRuleSetModel();
expectedRuleSet.setId(ruleSetId);
expectedRuleSet.setInclusionType("linked");
linkedRuleSets.getEntries()
.get(0).onModel().assertThat().isEqualTo(expectedRuleSet);
}
}

View File

@@ -0,0 +1,130 @@
/*
* #%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 java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
import org.alfresco.rest.model.RestCompositeConditionDefinitionModel;
import org.alfresco.rest.model.RestRuleModel;
public class RulesTestsUtils
{
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_ERROR_SCRIPT_DEFAULT = "error-script";
static final List<String> ruleTriggersDefault = List.of("inbound", "update", "outbound");
/**
* Create a rule model filled with default values.
*
* @return The created rule model.
*/
public static RestRuleModel createRuleModelWithModifiedValues()
{
RestRuleModel ruleModel = createRuleModelWithDefaultValues();
ruleModel.setDescription(RULE_DESCRIPTION_DEFAULT);
ruleModel.setEnabled(RULE_ENABLED_DEFAULT);
ruleModel.setCascade(RULE_CASCADE_DEFAULT);
ruleModel.setAsynchronous(RULE_ASYNC_DEFAULT);
ruleModel.setIsShared(RULE_SHARED_DEFAULT);
ruleModel.setTriggers(ruleTriggersDefault);
ruleModel.setErrorScript(RULE_ERROR_SCRIPT_DEFAULT);
return ruleModel;
}
public static RestRuleModel createRuleModelWithDefaultValues()
{
return createRuleModel(RULE_NAME_DEFAULT, List.of(createDefaultActionModel()));
}
public static RestRuleModel createRuleModel(String name)
{
return createRuleModel(name, List.of(createDefaultActionModel()));
}
/**
* Create a rule model.
*
* @param name The name for the rule.
* @param restActionModels Rule's actions.
* @return The created rule model.
*/
public static RestRuleModel createRuleModel(String name, List<RestActionBodyExecTemplateModel> restActionModels)
{
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName(name);
ruleModel.setActions(restActionModels);
return ruleModel;
}
/**
* Create a rule's action model.
*
* @return The created action model.
*/
public static RestActionBodyExecTemplateModel createDefaultActionModel()
{
RestActionBodyExecTemplateModel restActionModel = new RestActionBodyExecTemplateModel();
restActionModel.setActionDefinitionId("set-property-value");
restActionModel.setParams(Map.of("aspect-name", "cm:audio"));
return restActionModel;
}
public static List<RestActionBodyExecTemplateModel> addActionContextParams(List<RestActionBodyExecTemplateModel> inputActions)
{
inputActions.forEach(inputAction -> {
final Map<String, Serializable> params = new HashMap<>((Map<String, Serializable>) inputAction.getParams());
params.put("actionContext", "rule");
inputAction.setParams(params);
});
return inputActions;
}
public static RestActionBodyExecTemplateModel createCustomActionModel(String actionDefinitionId, Map<String, Serializable> params)
{
RestActionBodyExecTemplateModel restActionModel = new RestActionBodyExecTemplateModel();
restActionModel.setActionDefinitionId(actionDefinitionId);
restActionModel.setParams(params);
return restActionModel;
}
public static RestCompositeConditionDefinitionModel createEmptyConditionModel()
{
RestCompositeConditionDefinitionModel conditions = new RestCompositeConditionDefinitionModel();
conditions.setInverted(false);
conditions.setBooleanMode("and");
return conditions;
}
}

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)
.withCoreAPI()
.usingResource(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)
.withCoreAPI()
.usingResource(nonExistentFolder)
.usingIsInheritanceEnabledRuleSetting()
.retrieveSetting();
restClient.assertLastError().statusCodeIs(NOT_FOUND)
.containsSummary("The entity 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).withCoreAPI().usingResource(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)
.withCoreAPI()
.usingResource(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)
.withCoreAPI()
.usingResource(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).withCoreAPI().usingResource(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).withCoreAPI().usingResource(nonExistentFolder).usingIsInheritanceEnabledRuleSetting()
.updateSetting(updateBody);
restClient.assertLastError().statusCodeIs(NOT_FOUND)
.containsSummary("The entity 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).withCoreAPI().usingResource(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).withCoreAPI().usingResource(folder).usingIsInheritanceEnabledRuleSetting()
.updateSetting(updateBody);
restClient.assertLastError().statusCodeIs(FORBIDDEN)
.containsSummary("Insufficient permissions to manage rules");
}
}

View File

@@ -25,19 +25,20 @@
*/
package org.alfresco.rest.rules;
import static org.alfresco.rest.rules.RulesTestsUtils.createDefaultActionModel;
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.fail;
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.OK;
import java.util.List;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
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;
@@ -63,28 +64,32 @@ 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 = createRule("Rule name");
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update the rule.");
RestRuleModel updatedRuleModel = new RestRuleModel();
updatedRuleModel.setName("Updated rule name");
RestRuleModel updatedRuleModel = createRuleModel("Updated rule name");
RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), updatedRuleModel);
restClient.assertStatusCodeIs(OK);
updatedRule.assertThat().field("id").is(rule.getId())
.assertThat().field("name").is("Updated rule name");
.assertThat().field("name").is("Updated rule name")
.assertThat().field("isShared").isNull();
}
/** Check we get a 404 if trying to update a rule in a folder that doesn't exist. */
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void updateRuleForNonExistentFolder()
{
RestRuleModel rule = createRule("Rule name");
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update a rule in a non-existent folder.");
FolderModel nonExistentFolder = FolderModel.getRandomFolderModel();
@@ -103,7 +108,7 @@ public class UpdateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void updateRuleForNonExistentRuleSet()
{
RestRuleModel rule = createRule("Rule name");
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update a rule in a non-existent rule set.");
RestRuleModel updatedRuleModel = new RestRuleModel();
@@ -153,11 +158,10 @@ public class UpdateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void updateRuleToHaveEmptyName()
{
RestRuleModel rule = createRule("Rule name");
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update the rule to have no name.");
RestRuleModel updatedRuleModel = new RestRuleModel();
updatedRuleModel.setName("");
RestRuleModel updatedRuleModel = createRuleModel("");
restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet().updateRule(rule.getId(), updatedRuleModel);
restClient.assertLastError().statusCodeIs(BAD_REQUEST)
@@ -168,30 +172,49 @@ public class UpdateRulesTests extends RestTest
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
public void tryToUpdateRuleId()
{
RestRuleModel rule = createRule("Rule name");
RestRuleModel rule = createAndSaveRule("Rule name");
STEP("Try to update the rule id and check it isn't changed.");
RestRuleModel updatedRuleModel = new RestRuleModel();
RestRuleModel updatedRuleModel = createRuleModel("Rule name");
updatedRuleModel.setId("new-rule-id");
updatedRuleModel.setName("Rule name");
RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.updateRule(rule.getId(), updatedRuleModel);
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 = createRuleModel("Updated rule name");
RestRuleModel updatedRule = restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.include("isShared")
.updateRule(rule.getId(), updatedRuleModel);
updatedRule.assertThat().field("isShared").isNotNull();
}
private RestRuleModel createAndSaveRule(String name)
{
return createAndSaveRule(name, List.of(createDefaultActionModel()));
}
/**
* Create a rule.
* Create a rule for folder and store it.
*
* @param name The name for the rule.
* @param restActionModels Rule's actions.
* @return The created rule.
*/
private RestRuleModel createRule(String name)
private RestRuleModel createAndSaveRule(String name, List<RestActionBodyExecTemplateModel> restActionModels)
{
STEP("Create a rule called " + name);
RestRuleModel ruleModel = new RestRuleModel();
ruleModel.setName(name);
STEP("Create a rule called " + name + ", containing actions: " + restActionModels);
RestRuleModel ruleModel = createRuleModel(name, restActionModels);
return restClient.authenticateUser(user).withCoreAPI().usingNode(ruleFolder).usingDefaultRuleSet()
.createSingleRule(ruleModel);
.createSingleRule(ruleModel);
}
}

View File

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

View File

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

65
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.56</version>
<version>17.102-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -45,18 +45,18 @@
<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.19</dependency.alfresco-messaging-repo.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-greenmail.version>6.2</dependency.alfresco-greenmail.version>
<dependency.acs-event-model.version>0.0.15</dependency.acs-event-model.version>
<dependency.alfresco-transform-service.version>1.5.4-A3</dependency.alfresco-transform-service.version>
<dependency.alfresco-transform-core.version>2.7.0-A1</dependency.alfresco-transform-core.version>
<dependency.alfresco-greenmail.version>6.4</dependency.alfresco-greenmail.version>
<dependency.acs-event-model.version>0.0.16</dependency.acs-event-model.version>
<dependency.spring.version>5.3.21</dependency.spring.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>
@@ -74,15 +74,15 @@
<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.slf4j.version>1.7.36</dependency.slf4j.version>
<dependency.gytheio.version>0.16</dependency.gytheio.version>
<dependency.groovy.version>3.0.11</dependency.groovy.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.truezip.version>7.7.10</dependency.truezip.version>
<dependency.poi.version>5.2.2</dependency.poi.version>
<dependency.ooxml-schemas.version>1.4</dependency.ooxml-schemas.version>
<dependency.keycloak.version>15.0.2</dependency.keycloak.version>
<dependency.keycloak.version>18.0.0</dependency.keycloak.version>
<dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version>
<dependency.camel.version>3.15.0</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies (can cause dependency conflicts)-->
<dependency.activemq.version>5.17.1</dependency.activemq.version>
@@ -114,17 +114,17 @@
<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.0</dependency.postgresql.version>
<dependency.mysql.version>8.0.29</dependency.mysql.version>
<dependency.postgresql.version>42.4.1</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.97</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.rest-assured.version>5.1.1</dependency.rest-assured.version>
<dependency.tas-restapi.version>1.115</dependency.tas-restapi.version>
<dependency.tas-cmis.version>1.32</dependency.tas-cmis.version>
<dependency.tas-email.version>1.9</dependency.tas-email.version>
<dependency.tas-webdav.version>1.7</dependency.tas-webdav.version>
<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 +148,7 @@
<connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
<url>https://github.com/Alfresco/alfresco-community-repo</url>
<tag>17.56</tag>
<tag>HEAD</tag>
</scm>
<distributionManagement>
@@ -616,6 +616,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>
@@ -639,7 +645,7 @@
<dependency>
<groupId>com.github.junrar</groupId>
<artifactId>junrar</artifactId>
<version>7.5.2</version>
<version>7.5.3</version>
</dependency>
<dependency>
<groupId>com.github.fge</groupId>
@@ -877,6 +883,17 @@
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>${dependency.activiti.version}</version>
<exclusions>
<exclusion>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
@@ -894,7 +911,7 @@
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.40.1</version>
<version>0.40.2</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
@@ -920,7 +937,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -929,7 +946,7 @@
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.4.1</version>
<version>3.4.2</version>
</plugin>
<plugin>
<groupId>org.alfresco.maven.plugin</groupId>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>17.56</version>
<version>17.102-SNAPSHOT</version>
</parent>
<dependencies>
@@ -130,7 +130,7 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>8.2.0.v20160908</version>
<version>10.0.11</version>
<scope>test</scope>
<exclusions>
<exclusion>
@@ -142,19 +142,19 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-security</artifactId>
<version>8.2.0.v20160908</version>
<version>10.0.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>8.2.0.v20160908</version>
<version>10.0.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.alfresco.cmis.client</groupId>
<artifactId>alfresco-opencmis-extension</artifactId>
<version>2.0</version>
<version>2.1</version>
<scope>test</scope>
<exclusions>
<!-- Duplicates classes from jakarta.transaction:jakarta.transaction-api -->

View File

@@ -0,0 +1,64 @@
/*
* #%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.repo.web.scripts;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.MimetypeService;
import org.springframework.extensions.webscripts.WebScriptRequest;
public class MimeTypeUtil
{
/**
* Get the file mimetype from the file ContentReader, and if its null then set the mimetype to binary by default
* and try to get the correct one from file extension
*
*
* @param reader reader of the file in the request
* @param req request relating to the file
* @param mimetypeService MimetypeService
*
* @return mimetype of the file as a string
*/
public static String determineMimetype(ContentReader reader, WebScriptRequest req, MimetypeService mimetypeService)
{
String mimetype = reader.getMimetype();
if (mimetype == null || mimetype.length() == 0)
{
String extensionPath = req.getExtensionPath();
mimetype = MimetypeMap.MIMETYPE_BINARY;
int extIndex = extensionPath.lastIndexOf('.');
if (extIndex != -1)
{
String ext = extensionPath.substring(extIndex + 1);
mimetype = mimetypeService.getMimetype(ext);
}
}
return mimetype;
}
}

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
@@ -26,14 +26,18 @@
package org.alfresco.repo.web.scripts.content;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.web.scripts.MimeTypeUtil;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
@@ -65,6 +69,19 @@ public class ContentGet extends StreamContent implements ServletContextAware
private NamespaceService namespaceService;
private ContentService contentService;
private List<String> nonAttachContentTypes = Collections.emptyList();
/**
* @param nonAttachContentTypes List<String>
*/
public void setNonAttachContentTypes(List<String> nonAttachContentTypes)
{
if (nonAttachContentTypes != null && !nonAttachContentTypes.isEmpty())
{
this.nonAttachContentTypes = nonAttachContentTypes;
}
}
/**
* @param servletContext ServletContext
*/
@@ -121,9 +138,7 @@ public class ContentGet extends StreamContent implements ServletContextAware
{
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find " + reference.toString());
}
// determine attachment
boolean attach = Boolean.valueOf(req.getParameter("a"));
// render content
QName propertyQName = ContentModel.PROP_CONTENT;
@@ -140,6 +155,19 @@ public class ContentGet extends StreamContent implements ServletContextAware
propertyQName = QName.createQName(propertyName, namespaceService);
}
}
// determine attachment and force download for specific mimetypes - see PRODSEC-5862
boolean attach = Boolean.valueOf(req.getParameter("a"));
ContentReader reader = contentService.getReader(nodeRef, propertyQName);
String mimetype = MimeTypeUtil.determineMimetype(reader, req, mimetypeService);
if (!attach)
{
if (nonAttachContentTypes == null || !nonAttachContentTypes.contains(mimetype))
{
attach = true;
logger.warn("Ignored a=false for " + nodeRef.getId() + " since " + mimetype + " is not in the whitelist for non-attach content types");
}
}
// Stream the content
streamContentLocal(req, res, nodeRef, attach, propertyQName, null);

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco 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.repo.web.scripts.content;
import java.io.IOException;
@@ -33,7 +33,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.web.scripts.MimeTypeUtil;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
@@ -79,18 +79,7 @@ public class ContentInfo extends StreamContent
delegate.setAttachment(req, res, attach, attachFileName);
// establish mimetype
String mimetype = reader.getMimetype();
String extensionPath = req.getExtensionPath();
if (mimetype == null || mimetype.length() == 0)
{
mimetype = MimetypeMap.MIMETYPE_BINARY;
int extIndex = extensionPath.lastIndexOf('.');
if (extIndex != -1)
{
String ext = extensionPath.substring(extIndex + 1);
mimetype = mimetypeService.getMimetype(ext);
}
}
String mimetype = MimeTypeUtil.determineMimetype(reader, req, mimetypeService);
// set mimetype for the content and the character encoding + length for the stream
res.setContentType(mimetype);

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
@@ -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;
@@ -43,6 +44,7 @@ import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.filestore.FileContentReader;
import org.alfresco.repo.web.scripts.MimeTypeUtil;
import org.alfresco.sync.repo.events.EventPublisher;
import org.alfresco.repo.web.util.HttpRangeProcessor;
import org.alfresco.rest.framework.resource.content.CacheDirective;
@@ -58,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;
@@ -361,18 +364,7 @@ public class ContentStreamer implements ResourceLoaderAware
setAttachment(req, res, attach, attachFileName);
// establish mimetype
String mimetype = reader.getMimetype();
String extensionPath = req.getExtensionPath();
if (mimetype == null || mimetype.length() == 0)
{
mimetype = MimetypeMap.MIMETYPE_BINARY;
int extIndex = extensionPath.lastIndexOf('.');
if (extIndex != -1)
{
String ext = extensionPath.substring(extIndex + 1);
mimetype = mimetypeService.getMimetype(ext);
}
}
String mimetype = MimeTypeUtil.determineMimetype(reader, req, mimetypeService);
res.setHeader(HEADER_ACCEPT_RANGES, "bytes");
try
@@ -482,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
@@ -491,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);
}
}
}
@@ -506,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

@@ -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

@@ -0,0 +1,66 @@
/*
* #%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 java.util.List;
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;
/**
* Rule sets API.
*/
@Experimental
public interface RuleSets
{
/**
* Get rule sets for a folder.
*
* @param folderNodeId Folder node ID
* @param paging {@link Paging} information
* @param includes List of fields to include in the rule set
* @return {@link CollectionWithPagingInfo} containing a list page of rule sets
*/
CollectionWithPagingInfo<RuleSet> getRuleSets(String folderNodeId, List<String> includes, Paging paging);
/**
* Get the rule set with the given ID and check associations with the folder node.
*
* @param folderNodeId Folder node ID
* @param ruleSetId Rule set ID
* @param includes List of fields to include in the rule set
* @return {@link RuleSet} definition
*/
RuleSet getRuleSetById(String folderNodeId, String ruleSetId, List<String> includes);
/**
* Link a rule set to a folder
*/
RuleSetLink linkToRuleSet(String folderNodeId, String linkToNodeId);
}

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);
}

View File

@@ -26,6 +26,8 @@
package org.alfresco.rest.api;
import java.util.List;
import org.alfresco.rest.api.model.rules.Rule;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
@@ -33,8 +35,6 @@ import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.rule.RuleServiceException;
import java.util.List;
/**
* Folder node rules API.
*
@@ -47,10 +47,11 @@ public interface Rules
*
* @param folderNodeId - folder node ID
* @param ruleSetId - rule set ID
* @param includes - The list of optional fields to include in the response.
* @param paging - {@link Paging} information
* @return {@link CollectionWithPagingInfo} containing a list page of folder rules
*/
CollectionWithPagingInfo<Rule> getRules(String folderNodeId, String ruleSetId, Paging paging);
CollectionWithPagingInfo<Rule> getRules(String folderNodeId, String ruleSetId, List<String> includes, Paging paging);
/**
* Get rule for rule's ID and check associations with folder node and rule set node
@@ -58,9 +59,10 @@ public interface Rules
* @param folderNodeId - folder node ID
* @param ruleSetId - rule set ID
* @param ruleId - rule ID
* @param includes - The list of optional fields to include in the response.
* @return {@link Rule} definition
*/
Rule getRuleById(String folderNodeId, String ruleSetId, String ruleId);
Rule getRuleById(String folderNodeId, String ruleSetId, String ruleId, List<String> includes);
/**
* Create new rules (and potentially a rule set if "_default_" is supplied).
@@ -68,11 +70,12 @@ public interface Rules
* @param folderNodeId The node id of a folder.
* @param ruleSetId The id of a rule set (or "_default_" to use/create the default rule set for the folder).
* @param rule The definition of the rule.
* @param includes The list of optional fields to include in the response.
* @return The newly created rules.
* @throws InvalidArgumentException If the nodes are not the expected types, or the rule set does not correspond to the folder.
* @throws RuleServiceException If the folder is already linked to another rule set.
*/
List<Rule> createRules(String folderNodeId, String ruleSetId, List<Rule> rule);
List<Rule> createRules(String folderNodeId, String ruleSetId, List<Rule> rule, List<String> includes);
/**
* Update a rule.
@@ -81,9 +84,10 @@ public interface Rules
* @param ruleSetId The id of a rule set within the folder (or "_default_" to use the default rule set for the folder).
* @param ruleId The rule id.
* @param rule The new version of the rule.
* @param includes The list of optional fields to include in the response.
* @return The newly updated rule.
*/
Rule updateRuleById(String folderNodeId, String ruleSetId, String ruleId, Rule rule);
Rule updateRuleById(String folderNodeId, String ruleSetId, String ruleId, Rule rule, List<String> includes);
/**
* Delete rule for rule's ID and check associations with folder node and rule set node

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2021 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
@@ -713,6 +713,7 @@ public class CustomModelsImpl implements CustomModels
try
{
NodeRef nodeRef = customModelService.createDownloadNode(modelName, withForm);
nodeService.setProperty(nodeRef, ContentModel.PROP_NAME, modelName + DownloadsImpl.DEFAULT_ARCHIVE_EXTENSION);
return new CustomModelDownload(nodeRef);
}
catch (Exception ex)

View File

@@ -0,0 +1,156 @@
/*
* #%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.impl.rules;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.action.ParameterizedItemDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryException;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.json.JSONArray;
import org.json.JSONException;
@Experimental
public class ActionParameterConverter
{
private final DictionaryService dictionaryService;
private final ActionService actionService;
private final NamespaceService namespaceService;
public ActionParameterConverter(DictionaryService dictionaryService, ActionService actionService,
NamespaceService namespaceService)
{
this.dictionaryService = dictionaryService;
this.actionService = actionService;
this.namespaceService = namespaceService;
}
Map<String, Serializable> getConvertedParams(Map<String, Serializable> params, String name)
{
final Map<String, Serializable> parameters = new HashMap<>(params.size());
final ParameterizedItemDefinition definition = actionService.getActionDefinition(name);
if (definition == null)
{
throw new NotFoundException(NotFoundException.DEFAULT_MESSAGE_ID, new String[]{name});
}
for (Map.Entry<String, Serializable> param : params.entrySet())
{
final ParameterDefinition paramDef = definition.getParameterDefintion(param.getKey());
if (paramDef == null && !definition.getAdhocPropertiesAllowed())
{
throw new InvalidArgumentException(InvalidArgumentException.DEFAULT_MESSAGE_ID, new String[]{param.getKey(), name});
}
if (paramDef != null)
{
final QName typeQName = paramDef.getType();
parameters.put(param.getKey(), convertValue(typeQName, param.getValue()));
} else
{
parameters.put(param.getKey(), param.getValue().toString());
}
}
return parameters;
}
public Serializable convertParamFromServiceModel(Serializable param)
{
if (param instanceof QName)
{
return ((QName) param).toPrefixString(namespaceService);
}
else if (param instanceof NodeRef) {
return ((NodeRef) param).getId();
}
else
{
return param;
}
}
private Serializable convertValue(QName typeQName, Object propertyValue) throws JSONException
{
Serializable value;
final DataTypeDefinition typeDef = dictionaryService.getDataType(typeQName);
if (typeDef == null)
{
throw new NotFoundException(NotFoundException.DEFAULT_MESSAGE_ID, new String[]{typeQName.toPrefixString()});
}
if (propertyValue instanceof JSONArray)
{
final String javaClassName = typeDef.getJavaClassName();
try
{
Class.forName(javaClassName);
} catch (ClassNotFoundException e)
{
throw new DictionaryException("Java class " + javaClassName + " of property type " + typeDef.getName() + " is invalid", e);
}
final int length = ((JSONArray) propertyValue).length();
final List<Serializable> list = new ArrayList<>(length);
for (int i = 0; i < length; i++)
{
list.add(convertValue(typeQName, ((JSONArray) propertyValue).get(i)));
}
value = (Serializable) list;
}
else
{
if (typeQName.equals(DataTypeDefinition.QNAME) && typeQName.toString().contains(":"))
{
value = QName.createQName(propertyValue.toString(), namespaceService);
}
else if (typeQName.isMatch(DataTypeDefinition.NODE_REF))
{
value = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, propertyValue.toString());
}
else
{
value = (Serializable) DefaultTypeConverter.INSTANCE.convert(dictionaryService.getDataType(typeQName), propertyValue);
}
}
return value;
}
}

View File

@@ -0,0 +1,85 @@
/*
* #%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.impl.rules;
import static org.alfresco.repo.web.scripts.rule.AbstractRuleWebScript.CANNOT_CREATE_RULE;
import static org.alfresco.service.cmr.rule.RuleType.OUTBOUND;
import java.util.Collections;
import java.util.List;
import org.alfresco.repo.action.CompositeActionImpl;
import org.alfresco.repo.action.RuntimeActionService;
import org.alfresco.repo.action.access.ActionAccessRestriction;
import org.alfresco.repo.action.executer.CheckOutActionExecuter;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.rule.Rule;
import org.apache.commons.collections.CollectionUtils;
@Experimental
public class ActionPermissionValidator
{
private final RuntimeActionService runtimeActionService;
public ActionPermissionValidator(RuntimeActionService runtimeActionService)
{
this.runtimeActionService = runtimeActionService;
}
Rule validateRulePermissions(Rule rule)
{
final List<Action> actions = ((CompositeActionImpl) rule.getAction()).getActions();
checkRestrictedAccessActions(actions);
checkRuleOutboundHasNoCheckOutAction(rule, actions);
return rule;
}
private void checkRestrictedAccessActions(List<Action> actions) {
actions.forEach(action -> {
ActionAccessRestriction.setActionContext(action, ActionAccessRestriction.RULE_ACTION_CONTEXT);
runtimeActionService.verifyActionAccessRestrictions(action);
});
}
private void checkRuleOutboundHasNoCheckOutAction(Rule rule, List<Action> actions) {
//TODO: rule types should never be empty in final implementation
if (CollectionUtils.isNotEmpty(rule.getRuleTypes()) && rule.getRuleTypes().contains(OUTBOUND))
{
for (Action action : actions)
{
if (action.getActionDefinitionName().equalsIgnoreCase(CheckOutActionExecuter.NAME))
{
throw new InvalidArgumentException(CANNOT_CREATE_RULE);
}
}
}
}
}

View File

@@ -23,123 +23,39 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.api.impl;
package org.alfresco.rest.api.impl.rules;
import static org.alfresco.service.cmr.security.AccessStatus.ALLOWED;
import static org.alfresco.service.cmr.security.PermissionService.CHANGE_PERMISSIONS;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.rule.RuleModel;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.Rules;
import org.alfresco.rest.api.model.rules.Rule;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.rules.RuleSet;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.ListPage;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Responsible for validating nodes when working with rules. */
@Experimental
public class RulesImpl implements Rules
public class NodeValidator
{
private static final Logger LOGGER = LoggerFactory.getLogger(RulesImpl.class);
private static final String RULE_SET_EXPECTED_TYPE_NAME = "rule set";
private Nodes nodes;
private PermissionService permissionService;
private RuleService ruleService;
@Override
public CollectionWithPagingInfo<Rule> getRules(final String folderNodeId, final String ruleSetId, final Paging paging)
{
final NodeRef folderNodeRef = validateFolderNode(folderNodeId, false);
final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef);
final boolean isShared = isRuleSetNotNullAndShared(ruleSetNodeRef);
final List<Rule> rules = ruleService.getRules(folderNodeRef).stream()
.map(ruleModel -> Rule.from(ruleModel, isShared))
.collect(Collectors.toList());
return ListPage.of(rules, paging);
}
@Override
public Rule getRuleById(final String folderNodeId, final String ruleSetId, final String ruleId)
{
final NodeRef folderNodeRef = validateFolderNode(folderNodeId, false);
final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef);
final NodeRef ruleNodeRef = validateRuleNode(ruleId, ruleSetNodeRef);
return Rule.from(ruleService.getRule(ruleNodeRef), isRuleSetNotNullAndShared(ruleSetNodeRef));
}
@Override
public List<Rule> createRules(final String folderNodeId, final String ruleSetId, final List<Rule> rules)
{
final NodeRef folderNodeRef = validateFolderNode(folderNodeId, true);
// Don't validate the ruleset node if -default- is passed since we may need to create it.
final NodeRef ruleSetNodeRef = (RuleSet.isNotDefaultId(ruleSetId)) ? validateRuleSetNode(ruleSetId, folderNodeRef) : null;
return rules.stream()
.map(rule -> rule.toServiceModel(nodes))
.map(rule -> ruleService.saveRule(folderNodeRef, rule))
.map(rule -> Rule.from(rule, isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef)))
.collect(Collectors.toList());
}
@Override
public Rule updateRuleById(String folderNodeId, String ruleSetId, String ruleId, Rule rule)
{
LOGGER.debug("Updating rule in folder {}, rule set {}, rule {} to {}", folderNodeId, ruleSetId, ruleId, rule);
NodeRef folderNodeRef = validateFolderNode(folderNodeId, true);
NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef);
validateRuleNode(ruleId, ruleSetNodeRef);
boolean shared = isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef);
return Rule.from(ruleService.saveRule(folderNodeRef, rule.toServiceModel(nodes)), shared);
}
@Override
public void deleteRuleById(String folderNodeId, String ruleSetId, String ruleId)
{
final NodeRef folderNodeRef = validateFolderNode(folderNodeId, true);
final NodeRef ruleSetNodeRef = validateRuleSetNode(ruleSetId, folderNodeRef);
final NodeRef ruleNodeRef = validateRuleNode(ruleId, ruleSetNodeRef);
final org.alfresco.service.cmr.rule.Rule rule = ruleService.getRule(ruleNodeRef);
ruleService.removeRule(folderNodeRef, rule);
}
public void setNodes(Nodes nodes)
{
this.nodes = nodes;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
private PermissionService permissionService;
private NodeService nodeService;
/**
* Validates if folder node exists and the user has permission to use it.
@@ -150,23 +66,10 @@ public class RulesImpl implements Rules
* @throws InvalidArgumentException if node is not of an expected type
* @throws PermissionDeniedException if the user doesn't have the appropriate permission for the folder.
*/
private NodeRef validateFolderNode(final String folderNodeId, boolean requireChangePermission)
public NodeRef validateFolderNode(final String folderNodeId, boolean requireChangePermission)
{
final NodeRef nodeRef = nodes.validateOrLookupNode(folderNodeId, null);
if (requireChangePermission)
{
if (permissionService.hasPermission(nodeRef, CHANGE_PERMISSIONS) != ALLOWED)
{
throw new PermissionDeniedException("Insufficient permissions to manage rules.");
}
}
else
{
if (permissionService.hasReadPermission(nodeRef) != ALLOWED)
{
throw new PermissionDeniedException("Cannot read from this node!");
}
}
validatePermission(requireChangePermission, nodeRef);
verifyNodeType(nodeRef, ContentModel.TYPE_FOLDER, null);
return nodeRef;
@@ -180,21 +83,38 @@ public class RulesImpl implements Rules
* @return rule set node reference
* @throws InvalidArgumentException in case of not matching associated folder node
*/
private NodeRef validateRuleSetNode(final String ruleSetId, final NodeRef associatedFolderNodeRef)
public NodeRef validateRuleSetNode(final String ruleSetId, final NodeRef associatedFolderNodeRef)
{
if (RuleSet.isDefaultId(ruleSetId))
{
return ruleService.getRuleSetNode(associatedFolderNodeRef);
final NodeRef ruleSetNodeRef = ruleService.getRuleSetNode(associatedFolderNodeRef);
if (ruleSetNodeRef == null)
{
//folder doesn't have a -default- rule set
throw new RelationshipResourceNotFoundException(associatedFolderNodeRef.getId(), ruleSetId);
}
return ruleSetNodeRef;
}
final NodeRef ruleSetNodeRef = validateNode(ruleSetId, ContentModel.TYPE_SYSTEM_FOLDER, RULE_SET_EXPECTED_TYPE_NAME);
if (!ruleService.isRuleSetAssociatedWithFolder(ruleSetNodeRef, associatedFolderNodeRef)) {
if (!ruleService.isRuleSetAssociatedWithFolder(ruleSetNodeRef, associatedFolderNodeRef))
{
throw new InvalidArgumentException("Rule set is not associated with folder node!");
}
return ruleSetNodeRef;
}
public NodeRef validateRuleSetNode(String linkToNodeId, boolean requireChangePermission)
{
final Node ruleSetNode = nodes.getNode(linkToNodeId);
final ChildAssociationRef primaryParent = nodeService.getPrimaryParent(ruleSetNode.getNodeRef());
final NodeRef parentNode = primaryParent.getParentRef();
validatePermission(requireChangePermission, parentNode);
return parentNode;
}
/**
* Validates if rule node exists and associated rule set node matches.
*
@@ -203,7 +123,7 @@ public class RulesImpl implements Rules
* @return rule node reference
* @throws InvalidArgumentException in case of not matching associated rule set node
*/
private NodeRef validateRuleNode(final String ruleId, final NodeRef associatedRuleSetNodeRef)
public NodeRef validateRuleNode(final String ruleId, final NodeRef associatedRuleSetNodeRef)
{
final NodeRef ruleNodeRef = validateNode(ruleId, RuleModel.TYPE_RULE, null);
if (associatedRuleSetNodeRef != null && !ruleService.isRuleAssociatedWithRuleSet(ruleNodeRef, associatedRuleSetNodeRef))
@@ -222,16 +142,45 @@ public class RulesImpl implements Rules
return nodeRef;
}
private void validatePermission(boolean requireChangePermission, NodeRef nodeRef)
{
if (requireChangePermission)
{
if (permissionService.hasPermission(nodeRef, CHANGE_PERMISSIONS) != ALLOWED)
{
throw new PermissionDeniedException("Insufficient permissions to manage rules.");
}
}
else
{
if (permissionService.hasReadPermission(nodeRef) != ALLOWED)
{
throw new PermissionDeniedException("Cannot read from this node!");
}
}
}
private void verifyNodeType(final NodeRef nodeRef, final QName expectedType, final String expectedTypeName)
{
final Set<QName> expectedTypes = Set.of(expectedType);
if (!nodes.nodeMatches(nodeRef, expectedTypes, null)) {
final String expectedTypeLocalName = (expectedTypeName != null)? expectedTypeName : expectedType.getLocalName();
if (!nodes.nodeMatches(nodeRef, expectedTypes, null))
{
final String expectedTypeLocalName = (expectedTypeName != null) ? expectedTypeName : expectedType.getLocalName();
throw new InvalidArgumentException(String.format("NodeId of a %s is expected!", expectedTypeLocalName));
}
}
private boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef)
public boolean isRuleSetNode(String nodeId) {
try
{
validateNode(nodeId, ContentModel.TYPE_SYSTEM_FOLDER, RULE_SET_EXPECTED_TYPE_NAME);
return true;
} catch (InvalidArgumentException e) {
return false;
}
}
public boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef, final NodeRef folderNodeRef)
{
if (ruleSetNodeRef == null && folderNodeRef != null)
{
@@ -244,8 +193,28 @@ public class RulesImpl implements Rules
}
}
private boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef)
public boolean isRuleSetNotNullAndShared(final NodeRef ruleSetNodeRef)
{
return ruleSetNodeRef != null && ruleService.isRuleSetShared(ruleSetNodeRef);
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
public void setNodes(Nodes nodes)
{
this.nodes = nodes;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
}

View File

@@ -0,0 +1,64 @@
/*
* #%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.impl.rules;
import java.util.List;
import org.alfresco.rest.api.model.rules.Rule;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.rule.RuleService;
/** Responsible for creating {@link Rule} objects. */
@Experimental
public class RuleLoader
{
public static final String IS_SHARED = "isShared";
private RuleService ruleService;
private NodeValidator nodeValidator;
public Rule loadRule(org.alfresco.service.cmr.rule.Rule ruleModel, List<String> includes)
{
Rule rule = Rule.from(ruleModel);
if (includes != null && includes.contains(IS_SHARED))
{
NodeRef ruleSet = ruleService.getRuleSetNode(ruleModel.getNodeRef());
boolean isShared = nodeValidator.isRuleSetNotNullAndShared(ruleSet);
rule.setIsShared(isShared);
}
return rule;
}
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
public void setNodeValidator(NodeValidator nodeValidator)
{
this.nodeValidator = nodeValidator;
}
}

View File

@@ -0,0 +1,90 @@
/*
* #%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.impl.rules;
import static org.alfresco.rest.api.model.rules.InclusionType.INHERITED;
import static org.alfresco.rest.api.model.rules.InclusionType.LINKED;
import static org.alfresco.rest.api.model.rules.InclusionType.OWNED;
import java.util.List;
import org.alfresco.rest.api.model.rules.RuleSet;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
/** Responsible for converting a NodeRef into a {@link RuleSet} object. */
@Experimental
public class RuleSetLoader
{
protected static final String OWNING_FOLDER = "owningFolder";
protected static final String INCLUSION_TYPE = "inclusionType";
private NodeService nodeService;
/**
* Load a rule set for the given node ref.
*
* @param ruleSetNodeRef The rule set node.
* @param includes A list of fields to include.
* @return The rule set object.
*/
public RuleSet loadRuleSet(NodeRef ruleSetNodeRef, NodeRef folderNodeRef, List<String> includes)
{
String ruleSetId = ruleSetNodeRef.getId();
RuleSet ruleSet = RuleSet.of(ruleSetId);
if (includes != null)
{
NodeRef parentRef = nodeService.getPrimaryParent(ruleSetNodeRef).getParentRef();
if (includes.contains(OWNING_FOLDER))
{
ruleSet.setOwningFolder(parentRef);
}
if (includes.contains(INCLUSION_TYPE))
{
// In the case that a rule set applies to the given folder for multiple reasons then priority is given to owned, then linked, then inherited.
if (parentRef.equals(folderNodeRef))
{
ruleSet.setInclusionType(OWNED);
}
else
{
boolean linked = nodeService.getParentAssocs(ruleSetNodeRef)
.stream().map(ChildAssociationRef::getParentRef)
.anyMatch(folderNodeRef::equals);
ruleSet.setInclusionType(linked ? LINKED : INHERITED);
}
}
}
return ruleSet;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
}

View File

@@ -0,0 +1,134 @@
/*
* #%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.impl.rules;
import static java.util.stream.Collectors.toList;
import java.util.List;
import java.util.Optional;
import org.alfresco.repo.rule.RuleModel;
import org.alfresco.repo.rule.RuntimeRuleService;
import org.alfresco.rest.api.RuleSets;
import org.alfresco.rest.api.model.rules.RuleSet;
import org.alfresco.rest.api.model.rules.RuleSetLink;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.ListPage;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.rule.RuleService;
@Experimental
public class RuleSetsImpl implements RuleSets
{
private RuleSetLoader ruleSetLoader;
private RuleService ruleService;
private NodeValidator validator;
private NodeService nodeService;
private RuntimeRuleService runtimeRuleService;
@Override
public CollectionWithPagingInfo<RuleSet> getRuleSets(String folderNodeId, List<String> includes, Paging paging)
{
NodeRef folderNode = validator.validateFolderNode(folderNodeId, false);
NodeRef ruleSetNode = ruleService.getRuleSetNode(folderNode);
List<RuleSet> ruleSets = Optional.ofNullable(ruleSetNode)
.map(nodeRef -> ruleSetLoader.loadRuleSet(nodeRef, folderNode, includes))
.stream().collect(toList());
return ListPage.of(ruleSets, paging);
}
@Override
public RuleSet getRuleSetById(String folderNodeId, String ruleSetId, List<String> includes)
{
NodeRef folderNode = validator.validateFolderNode(folderNodeId, false);
NodeRef ruleSetNode = validator.validateRuleSetNode(ruleSetId, folderNode);
return ruleSetLoader.loadRuleSet(ruleSetNode, folderNode, includes);
}
@Override
public RuleSetLink linkToRuleSet(String folderNodeId, String linkToNodeId)
{
final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId,true);
final boolean isRuleSetNode = validator.isRuleSetNode(linkToNodeId);
final NodeRef linkToNodeRef = isRuleSetNode
? validator.validateRuleSetNode(linkToNodeId, true)
: validator.validateFolderNode(linkToNodeId, true);
//The target node should have pre-existing rules to link to
if (!ruleService.hasRules(linkToNodeRef)) {
throw new InvalidArgumentException("The target node has no rules to link.");
}
//The folder shouldn't have any pre-existing rules
if (ruleService.hasRules(folderNodeRef)) {
throw new InvalidArgumentException("Unable to link to a ruleset because the folder has pre-existing rules or is already linked to a ruleset.");
}
// Create the destination folder as a secondary child of the first
NodeRef ruleSetNodeRef = runtimeRuleService.getSavedRuleFolderAssoc(linkToNodeRef).getChildRef();
// The required aspect will automatically be added to the node
nodeService.addChild(folderNodeRef, ruleSetNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER);
RuleSetLink ruleSetLink = new RuleSetLink();
ruleSetLink.setId(ruleSetNodeRef.getId());
return ruleSetLink;
}
public void setRuleSetLoader(RuleSetLoader ruleSetLoader)
{
this.ruleSetLoader = ruleSetLoader;
}
public void setValidator(NodeValidator validator)
{
this.validator = validator;
}
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setRuntimeRuleService(RuntimeRuleService runtimeRuleService)
{
this.runtimeRuleService = runtimeRuleService;
}
}

View File

@@ -0,0 +1,107 @@
/*
* #%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.impl.rules;
import static org.alfresco.repo.rule.RuleModel.ASPECT_IGNORE_INHERITED_RULES;
import static org.alfresco.rest.api.model.rules.RuleSetting.IS_INHERITANCE_ENABLED_KEY;
import java.util.Collections;
import org.alfresco.rest.api.RuleSettings;
import org.alfresco.rest.api.model.rules.RuleSetting;
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
@Experimental
public class RuleSettingsImpl implements RuleSettings
{
private NodeValidator validator;
private NodeService nodeService;
@Override
public RuleSetting getRuleSetting(String folderId, String ruleSettingKey)
{
NodeRef folderNode = validator.validateFolderNode(folderId, false);
switch (ruleSettingKey)
{
case IS_INHERITANCE_ENABLED_KEY:
return getIsInheritanceEnabled(folderNode);
default:
throw new NotFoundException("Unrecognised rule setting key " + ruleSettingKey);
}
}
private RuleSetting getIsInheritanceEnabled(NodeRef folderNode)
{
boolean inheritanceDisabled = nodeService.hasAspect(folderNode, ASPECT_IGNORE_INHERITED_RULES);
return RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(!inheritanceDisabled).create();
}
@Override
public RuleSetting setRuleSetting(String folderId, RuleSetting ruleSetting)
{
NodeRef folderNode = validator.validateFolderNode(folderId, true);
switch (ruleSetting.getKey())
{
case IS_INHERITANCE_ENABLED_KEY:
return updateIsInheritanceEnabled(folderNode, ruleSetting.getValue());
default:
throw new NotFoundException("Unrecognised rule setting key " + ruleSetting.getKey());
}
}
private RuleSetting updateIsInheritanceEnabled(NodeRef folderNode, Object value)
{
if (!(value instanceof Boolean))
{
throw new IllegalArgumentException("Rule setting " + IS_INHERITANCE_ENABLED_KEY + " requires a boolean value.");
}
if ((boolean) value)
{
nodeService.removeAspect(folderNode, ASPECT_IGNORE_INHERITED_RULES);
}
else
{
nodeService.addAspect(folderNode, ASPECT_IGNORE_INHERITED_RULES, Collections.emptyMap());
}
return RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(value).create();
}
public void setValidator(NodeValidator validator)
{
this.validator = validator;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
}

View File

@@ -0,0 +1,177 @@
/*
* #%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.impl.rules;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.Rules;
import org.alfresco.rest.api.model.rules.Rule;
import org.alfresco.rest.api.model.rules.RuleSet;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.ListPage;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.CompositeAction;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.rule.RuleService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Experimental
public class RulesImpl implements Rules
{
private static final Logger LOGGER = LoggerFactory.getLogger(RulesImpl.class);
private Nodes nodes;
private RuleService ruleService;
private NodeValidator validator;
private RuleLoader ruleLoader;
private ActionParameterConverter actionParameterConverter;
private ActionPermissionValidator actionPermissionValidator;
@Override
public CollectionWithPagingInfo<Rule> getRules(final String folderNodeId,
final String ruleSetId,
final List<String> includes,
final Paging paging)
{
final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, false);
validator.validateRuleSetNode(ruleSetId, folderNodeRef);
final List<Rule> rules = ruleService.getRules(folderNodeRef).stream()
.map(ruleModel -> loadRuleAndConvertActionParams(ruleModel, includes))
.collect(Collectors.toList());
return ListPage.of(rules, paging);
}
@Override
public Rule getRuleById(final String folderNodeId, final String ruleSetId, final String ruleId, final List<String> includes)
{
final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, false);
final NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef);
final NodeRef ruleNodeRef = validator.validateRuleNode(ruleId, ruleSetNodeRef);
return loadRuleAndConvertActionParams(ruleService.getRule(ruleNodeRef), includes);
}
@Override
public List<Rule> createRules(final String folderNodeId, final String ruleSetId, final List<Rule> rules, final List<String> includes)
{
final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, true);
// Don't validate the ruleset node if -default- is passed since we may need to create it.
if (RuleSet.isNotDefaultId(ruleSetId))
{
validator.validateRuleSetNode(ruleSetId, folderNodeRef);
}
return rules.stream()
.map(this::mapToServiceModelAndValidateActions)
.map(rule -> ruleService.saveRule(folderNodeRef, rule))
.map(rule -> loadRuleAndConvertActionParams(rule, includes))
.collect(Collectors.toList());
}
@Override
public Rule updateRuleById(String folderNodeId, String ruleSetId, String ruleId, Rule rule, List<String> includes)
{
LOGGER.debug("Updating rule in folder {}, rule set {}, rule {} to {}", folderNodeId, ruleSetId, ruleId, rule);
NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, true);
NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef);
validator.validateRuleNode(ruleId, ruleSetNodeRef);
return ruleLoader.loadRule(ruleService.saveRule(folderNodeRef, mapToServiceModelAndValidateActions(rule)), includes);
}
@Override
public void deleteRuleById(String folderNodeId, String ruleSetId, String ruleId)
{
final NodeRef folderNodeRef = validator.validateFolderNode(folderNodeId, true);
final NodeRef ruleSetNodeRef = validator.validateRuleSetNode(ruleSetId, folderNodeRef);
final NodeRef ruleNodeRef = validator.validateRuleNode(ruleId, ruleSetNodeRef);
final org.alfresco.service.cmr.rule.Rule rule = ruleService.getRule(ruleNodeRef);
ruleService.removeRule(folderNodeRef, rule);
}
private org.alfresco.service.cmr.rule.Rule mapToServiceModelAndValidateActions(Rule rule)
{
final org.alfresco.service.cmr.rule.Rule serviceModelRule = rule.toServiceModel(nodes);
final CompositeAction compositeAction = (CompositeAction) serviceModelRule.getAction();
compositeAction.getActions().forEach(action -> action.setParameterValues(
actionParameterConverter.getConvertedParams(action.getParameterValues(), action.getActionDefinitionName())));
return actionPermissionValidator.validateRulePermissions(serviceModelRule);
}
private Rule loadRuleAndConvertActionParams(org.alfresco.service.cmr.rule.Rule ruleModel, List<String> includes)
{
final Rule rule = ruleLoader.loadRule(ruleModel, includes);
rule.getActions()
.forEach(a -> a.setParams(a.getParams().entrySet()
.stream()
.collect(Collectors
.toMap(Map.Entry::getKey, e -> actionParameterConverter.convertParamFromServiceModel(e.getValue())))
)
);
return rule;
}
public void setNodes(Nodes nodes)
{
this.nodes = nodes;
}
public void setRuleService(RuleService ruleService)
{
this.ruleService = ruleService;
}
public void setValidator(NodeValidator validator)
{
this.validator = validator;
}
public void setRuleLoader(RuleLoader ruleLoader)
{
this.ruleLoader = ruleLoader;
}
public void setActionParameterConverter(ActionParameterConverter actionParameterConverter)
{
this.actionParameterConverter = actionParameterConverter;
}
public void setActionPermissionValidator(ActionPermissionValidator actionPermissionValidator)
{
this.actionPermissionValidator = actionPermissionValidator;
}
}

View File

@@ -0,0 +1,169 @@
/*
* #%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.model.rules;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.CompositeActionImpl;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.GUID;
@Experimental
public class Action
{
private String actionDefinitionId;
private Map<String, Serializable> params;
/**
* Converts service POJO action to REST model action.
*
* @param actionModel - {@link org.alfresco.service.cmr.action.Action} service POJO
* @return {@link Action} REST model
*/
public static Action from(final org.alfresco.service.cmr.action.Action actionModel)
{
if (actionModel == null)
{
return null;
}
final Action.Builder builder = builder().actionDefinitionId(actionModel.getActionDefinitionName());
if (actionModel.getParameterValues() != null)
{
builder.params(new HashMap<>(actionModel.getParameterValues()));
}
return builder.create();
}
/**
* Convert the REST model object to the equivalent service POJO.
*
* @param nodeRef The node reference.
* @return The action service POJO.
*/
public org.alfresco.service.cmr.action.Action toServiceModel(final NodeRef nodeRef)
{
return new ActionImpl(nodeRef, GUID.generate(), this.actionDefinitionId, params);
}
/**
* Convert the REST model objects to composite action service POJO.
*
* @param actions List of actions.
* @return The composite action service POJO.
*/
public static org.alfresco.service.cmr.action.Action toCompositeAction(final List<Action> actions) {
if (actions == null)
{
return null;
}
final org.alfresco.service.cmr.action.CompositeAction compositeAction = new CompositeActionImpl(null, GUID.generate());
actions.forEach(action -> compositeAction.addAction(action.toServiceModel(null)));
return compositeAction;
}
public String getActionDefinitionId()
{
return actionDefinitionId;
}
public void setActionDefinitionId(String actionDefinitionId)
{
this.actionDefinitionId = actionDefinitionId;
}
public Map<String, Serializable> getParams()
{
return params;
}
public void setParams(Map<String, Serializable> params)
{
this.params = params;
}
@Override
public String toString()
{
return "Action{" + "actionDefinitionId='" + actionDefinitionId + '\'' + ", params=" + params + '}';
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Action action = (Action) o;
return Objects.equals(actionDefinitionId, action.actionDefinitionId) && Objects.equals(params, action.params);
}
@Override
public int hashCode()
{
return Objects.hash(actionDefinitionId, params);
}
public static Builder builder()
{
return new Builder();
}
public static class Builder
{
private String actionDefinitionId;
private Map<String, Serializable> params;
public Builder actionDefinitionId(String actionDefinitionId)
{
this.actionDefinitionId = actionDefinitionId;
return this;
}
public Builder params(Map<String, Serializable> params)
{
this.params = params;
return this;
}
public Action create() {
final Action action = new Action();
action.setActionDefinitionId(actionDefinitionId);
action.setParams(params);
return action;
}
}
}

View File

@@ -0,0 +1,230 @@
/*
* #%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.model.rules;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.ActionCondition;
import org.apache.commons.collections.CollectionUtils;
@Experimental
public class CompositeCondition
{
private boolean inverted;
private ConditionOperator booleanMode = ConditionOperator.AND;
private List<CompositeCondition> compositeConditions;
private List<SimpleCondition> simpleConditions;
/**
* Converts Action conditions (service POJO) list to composite condition (REST model).
*
* @param actionConditions - list of {@link ActionCondition} service POJOs
* @return {@link CompositeCondition} REST model
*/
public static CompositeCondition from(final List<ActionCondition> actionConditions)
{
if (actionConditions == null)
{
return null;
}
final CompositeCondition conditions = new CompositeCondition();
conditions.compositeConditions = new ArrayList<>();
// group action conditions by inversion flag
actionConditions.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(ActionCondition::getInvertCondition))
// map action condition sub lists
.forEach((inverted, actionConditionsPart) -> Optional.ofNullable(CompositeCondition.ofActionConditions(actionConditionsPart, inverted, ConditionOperator.AND))
// if composite condition present add to final list
.ifPresent(compositeCondition -> conditions.compositeConditions.add(compositeCondition)));
if (conditions.compositeConditions.isEmpty()) {
conditions.compositeConditions = null;
}
return conditions;
}
private static CompositeCondition ofActionConditions(final List<ActionCondition> actionConditions, final boolean inverted, final ConditionOperator conditionOperator)
{
if (actionConditions == null)
{
return null;
}
return ofSimpleConditions(SimpleCondition.listOf(actionConditions), inverted, conditionOperator);
}
/**
* Creates a composite condition instance of simple conditions.
*
* @param simpleConditions - list of {@link SimpleCondition}
* @param inverted - determines if condition should be inverted
* @param conditionOperator - determines the operation, see {@link ConditionOperator}
* @return {@link CompositeCondition}
*/
public static CompositeCondition ofSimpleConditions(final List<SimpleCondition> simpleConditions, final boolean inverted, final ConditionOperator conditionOperator)
{
return of(simpleConditions, null, inverted, conditionOperator);
}
private static CompositeCondition of(final List<SimpleCondition> simpleConditions, final List<CompositeCondition> compositeConditions,
final boolean inverted, final ConditionOperator conditionOperator)
{
if (CollectionUtils.isEmpty(simpleConditions) && CollectionUtils.isEmpty(compositeConditions))
{
return null;
}
return builder()
.inverted(inverted)
.booleanMode(conditionOperator)
.simpleConditions(simpleConditions)
.compositeConditions(compositeConditions)
.create();
}
public boolean isInverted()
{
return inverted;
}
public void setInverted(boolean inverted)
{
this.inverted = inverted;
}
public String getBooleanMode()
{
if (booleanMode == null)
{
return null;
}
return booleanMode.name().toLowerCase();
}
public void setBooleanMode(ConditionOperator booleanMode)
{
this.booleanMode = booleanMode;
}
public List<CompositeCondition> getCompositeConditions()
{
return compositeConditions;
}
public void setCompositeConditions(List<CompositeCondition> compositeConditions)
{
this.compositeConditions = compositeConditions;
}
public List<SimpleCondition> getSimpleConditions()
{
return simpleConditions;
}
public void setSimpleConditions(List<SimpleCondition> simpleConditions)
{
this.simpleConditions = simpleConditions;
}
@Override
public String toString()
{
return "CompositeCondition{" + "inverted=" + inverted + ", booleanMode=" + booleanMode + ", compositeConditions=" + compositeConditions + ", simpleConditions="
+ simpleConditions + '}';
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
CompositeCondition that = (CompositeCondition) o;
return inverted == that.inverted && booleanMode == that.booleanMode && Objects.equals(compositeConditions, that.compositeConditions) && Objects.equals(
simpleConditions, that.simpleConditions);
}
@Override
public int hashCode()
{
return Objects.hash(inverted, booleanMode, compositeConditions, simpleConditions);
}
public static Builder builder()
{
return new Builder();
}
public static class Builder
{
private boolean inverted;
private ConditionOperator booleanMode = ConditionOperator.AND;
private List<CompositeCondition> compositeConditions;
private List<SimpleCondition> simpleConditions;
public Builder inverted(boolean inverted)
{
this.inverted = inverted;
return this;
}
public Builder booleanMode(ConditionOperator booleanMode)
{
this.booleanMode = booleanMode;
return this;
}
public Builder compositeConditions(List<CompositeCondition> compositeConditions)
{
this.compositeConditions = compositeConditions;
return this;
}
public Builder simpleConditions(List<SimpleCondition> simpleConditions)
{
this.simpleConditions = simpleConditions;
return this;
}
public CompositeCondition create()
{
final CompositeCondition condition = new CompositeCondition();
condition.setInverted(inverted);
condition.setBooleanMode(booleanMode);
condition.setCompositeConditions(compositeConditions);
condition.setSimpleConditions(simpleConditions);
return condition;
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* #%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.model.rules;
import org.alfresco.service.Experimental;
@Experimental
public enum ConditionOperator
{
AND, OR
}

View File

@@ -0,0 +1,59 @@
/*
* #%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.model.rules;
import com.fasterxml.jackson.annotation.JsonValue;
import org.alfresco.service.Experimental;
/** The reason why a rule set applies to a folder. */
@Experimental
public enum InclusionType
{
OWNED, INHERITED, LINKED;
/**
* Load an InclusionType from a given string (case insensitively).
*
* @param inclusionType The given string.
* @return The inclusion type.
*/
public static InclusionType from(String inclusionType)
{
return InclusionType.valueOf(inclusionType.toUpperCase());
}
/**
* The lower case version of the inclusion type.
*
* @return A lowercase string.
*/
@JsonValue
public String toString()
{
return super.toString().toLowerCase();
}
}

View File

@@ -26,20 +26,16 @@
package org.alfresco.rest.api.model.rules;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.executer.ScriptActionExecuter;
import org.alfresco.repo.action.executer.SetPropertyValueActionExecuter;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.framework.resource.UniqueId;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.CompositeAction;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.GUID;
@@ -52,9 +48,11 @@ public class Rule
private boolean enabled;
private boolean cascade;
private boolean asynchronous;
private boolean shared;
private Boolean isShared;
private String errorScript;
private List<RuleTrigger> triggers;
private List<RuleTrigger> triggers = List.of(RuleTrigger.INBOUND);
private CompositeCondition conditions;
private List<Action> actions;
/**
* Converts service POJO rule to REST model rule.
@@ -62,7 +60,7 @@ public class Rule
* @param ruleModel - {@link org.alfresco.service.cmr.rule.Rule} service POJO
* @return {@link Rule} REST model
*/
public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel, final boolean shared)
public static Rule from(final org.alfresco.service.cmr.rule.Rule ruleModel)
{
if (ruleModel == null)
{
@@ -74,8 +72,7 @@ public class Rule
.description(ruleModel.getDescription())
.enabled(!ruleModel.getRuleDisabled())
.cascade(ruleModel.isAppliedToChildren())
.asynchronous(ruleModel.getExecuteAsynchronously())
.shared(shared);
.asynchronous(ruleModel.getExecuteAsynchronously());
if (ruleModel.getNodeRef() != null) {
builder.id(ruleModel.getNodeRef().getId());
@@ -84,9 +81,17 @@ public class Rule
{
builder.triggers(ruleModel.getRuleTypes().stream().map(RuleTrigger::of).collect(Collectors.toList()));
}
if (ruleModel.getAction() != null && ruleModel.getAction().getCompensatingAction() != null && ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF) != null)
if (ruleModel.getAction() != null)
{
builder.errorScript(ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF).toString());
builder.conditions(CompositeCondition.from(ruleModel.getAction().getActionConditions()));
if (ruleModel.getAction().getCompensatingAction() != null && ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF) != null)
{
builder.errorScript(ruleModel.getAction().getCompensatingAction().getParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF).toString());
}
if (ruleModel.getAction() instanceof CompositeAction && ((CompositeAction) ruleModel.getAction()).getActions() != null)
{
builder.actions(((CompositeAction) ruleModel.getAction()).getActions().stream().map(Action::from).collect(Collectors.toList()));
}
}
return builder.create();
@@ -100,20 +105,25 @@ public class Rule
*/
public org.alfresco.service.cmr.rule.Rule toServiceModel(Nodes nodes)
{
org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule();
if (id != null)
{
NodeRef nodeRef = nodes.validateOrLookupNode(id, null);
ruleModel.setNodeRef(nodeRef);
}
final org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule();
final NodeRef nodeRef = (id != null) ? nodes.validateOrLookupNode(id, null) : null;
ruleModel.setNodeRef(nodeRef);
ruleModel.setTitle(name);
// TODO: Once we have actions working properly then this needs to be replaced.
Map<String, Serializable> parameters = Map.of(
SetPropertyValueActionExecuter.PARAM_PROPERTY, ContentModel.PROP_TITLE,
SetPropertyValueActionExecuter.PARAM_VALUE, "UPDATED:" + GUID.generate());
org.alfresco.service.cmr.action.Action action = new ActionImpl(null, GUID.generate(), SetPropertyValueActionExecuter.NAME, parameters);
ruleModel.setAction(action);
ruleModel.setDescription(description);
ruleModel.setRuleDisabled(!enabled);
ruleModel.applyToChildren(cascade);
ruleModel.setExecuteAsynchronously(asynchronous);
if (triggers != null)
{
ruleModel.setRuleTypes(triggers.stream().map(RuleTrigger::getValue).collect(Collectors.toList()));
}
ruleModel.setAction(Action.toCompositeAction(actions));
if (errorScript != null)
{
final org.alfresco.service.cmr.action.Action compensatingAction = new ActionImpl(null, GUID.generate(), ScriptActionExecuter.NAME);
compensatingAction.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, errorScript);
ruleModel.getAction().setCompensatingAction(compensatingAction);
}
return ruleModel;
}
@@ -189,36 +199,64 @@ public class Rule
this.errorScript = errorScript;
}
public boolean isShared()
public Boolean isIsShared()
{
return shared;
return isShared;
}
public void setShared(boolean shared)
public void setIsShared(Boolean shared)
{
this.shared = shared;
this.isShared = shared;
}
public List<RuleTrigger> getTriggers()
public List<String> getTriggers()
{
return triggers;
if (triggers == null)
{
return null;
}
return triggers.stream().map(RuleTrigger::getValue).collect(Collectors.toList());
}
public void setTriggers(List<RuleTrigger> triggers)
public void setTriggers(List<String> triggers)
{
if (triggers != null)
{
this.triggers = triggers.stream().map(RuleTrigger::of).collect(Collectors.toList());
}
}
public void setRuleTriggers(List<RuleTrigger> triggers)
{
this.triggers = triggers;
}
public List<Void> getActions()
public CompositeCondition getConditions()
{
return Collections.emptyList();
return conditions;
}
public void setConditions(CompositeCondition conditions)
{
this.conditions = conditions;
}
public List<Action> getActions()
{
return actions;
}
public void setActions(List<Action> actions)
{
this.actions = actions;
}
@Override
public String toString()
{
return "Rule{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", description='" + description + '\'' + ", enabled=" + enabled + ", cascade=" + cascade
+ ", asynchronous=" + asynchronous + ", shared=" + shared + ", errorScript='" + errorScript + '\'' + ", triggers=" + triggers + '}';
+ ", asynchronous=" + asynchronous + ", isShared=" + isShared + ", errorScript='" + errorScript + '\'' + ", triggers=" + triggers + ", conditions=" + conditions
+ ", actions=" + actions + '}';
}
@Override
@@ -229,14 +267,23 @@ public class Rule
if (o == null || getClass() != o.getClass())
return false;
Rule rule = (Rule) o;
return enabled == rule.enabled && cascade == rule.cascade && asynchronous == rule.asynchronous && shared == rule.shared && Objects.equals(id, rule.id) && Objects.equals(
name, rule.name) && Objects.equals(description, rule.description) && Objects.equals(errorScript, rule.errorScript) && Objects.equals(triggers, rule.triggers);
return enabled == rule.enabled
&& cascade == rule.cascade
&& asynchronous == rule.asynchronous
&& Objects.equals(isShared, rule.isShared)
&& Objects.equals(id, rule.id)
&& Objects.equals(name, rule.name)
&& Objects.equals(description, rule.description)
&& Objects.equals(errorScript, rule.errorScript)
&& Objects.equals(triggers, rule.triggers)
&& Objects.equals(conditions, rule.conditions)
&& Objects.equals(actions, rule.actions);
}
@Override
public int hashCode()
{
return Objects.hash(id, name, description, enabled, cascade, asynchronous, shared, errorScript, triggers);
return Objects.hash(id, name, description, enabled, cascade, asynchronous, isShared, errorScript, triggers, conditions, actions);
}
public static Builder builder()
@@ -253,9 +300,11 @@ public class Rule
private boolean enabled;
private boolean cascade;
private boolean asynchronous;
private boolean shared;
private Boolean isShared;
private String errorScript;
private List<RuleTrigger> triggers;
private List<RuleTrigger> triggers = List.of(RuleTrigger.INBOUND);
private CompositeCondition conditions;
private List<Action> actions;
public Builder id(String id)
{
@@ -293,9 +342,9 @@ public class Rule
return this;
}
public Builder shared(boolean shared)
public Builder isShared(Boolean isShared)
{
this.shared = shared;
this.isShared = isShared;
return this;
}
@@ -311,6 +360,18 @@ public class Rule
return this;
}
public Builder conditions(CompositeCondition conditions)
{
this.conditions = conditions;
return this;
}
public Builder actions(List<Action> actions)
{
this.actions = actions;
return this;
}
public Rule create()
{
Rule rule = new Rule();
@@ -320,9 +381,11 @@ public class Rule
rule.setEnabled(enabled);
rule.setCascade(cascade);
rule.setAsynchronous(asynchronous);
rule.setShared(shared);
rule.setIsShared(isShared);
rule.setErrorScript(errorScript);
rule.setTriggers(triggers);
rule.setRuleTriggers(triggers);
rule.setConditions(conditions);
rule.setActions(actions);
return rule;
}
}

View File

@@ -27,8 +27,10 @@
package org.alfresco.rest.api.model.rules;
import java.util.Objects;
import java.util.StringJoiner;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.NodeRef;
@Experimental
public class RuleSet
@@ -36,6 +38,8 @@ public class RuleSet
public static final String DEFAULT_ID = "-default-";
private String id;
private NodeRef owningFolder;
private InclusionType inclusionType;
public static RuleSet of(String id)
{
@@ -44,14 +48,6 @@ public class RuleSet
.create();
}
public boolean isNotDefaultId() {
return isNotDefaultId(this.id);
}
public boolean isDefaultId() {
return isDefaultId(this.id);
}
public static boolean isNotDefaultId(final String id) {
return !isDefaultId(id);
}
@@ -70,10 +66,36 @@ public class RuleSet
this.id = id;
}
public NodeRef getOwningFolder()
{
return owningFolder;
}
public void setOwningFolder(NodeRef owningFolder)
{
this.owningFolder = owningFolder;
}
public InclusionType getInclusionType()
{
return inclusionType;
}
public void setInclusionType(InclusionType inclusionType)
{
this.inclusionType = inclusionType;
}
@Override
public String toString()
{
return "RuleSet{" + "id='" + id + '\'' + '}';
return "RuleSet{"
+ new StringJoiner(", ")
.add("id='" + id + "'")
.add("owningFolder='" + owningFolder + "'")
.add("inclusionType='" + inclusionType + "'")
.toString()
+ '}';
}
@Override
@@ -84,13 +106,15 @@ public class RuleSet
if (o == null || getClass() != o.getClass())
return false;
RuleSet ruleSet = (RuleSet) o;
return Objects.equals(id, ruleSet.id);
return Objects.equals(id, ruleSet.id)
&& Objects.equals(owningFolder, ruleSet.owningFolder)
&& inclusionType == ruleSet.inclusionType;
}
@Override
public int hashCode()
{
return Objects.hash(id);
return Objects.hash(id, owningFolder, inclusionType);
}
public static Builder builder()
@@ -101,6 +125,8 @@ public class RuleSet
public static class Builder
{
private String id;
private NodeRef owningFolder;
private InclusionType inclusionType;
public Builder id(String id)
{
@@ -108,10 +134,24 @@ public class RuleSet
return this;
}
public Builder owningFolder(NodeRef owningFolder)
{
this.owningFolder = owningFolder;
return this;
}
public Builder inclusionType(InclusionType inclusionType)
{
this.inclusionType = inclusionType;
return this;
}
public RuleSet create()
{
final RuleSet ruleSet = new RuleSet();
ruleSet.setId(id);
ruleSet.setOwningFolder(owningFolder);
ruleSet.setInclusionType(inclusionType);
return ruleSet;
}
}

View File

@@ -0,0 +1,46 @@
/*
* #%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.model.rules;
public class RuleSetLink
{
/**
* This id is referring to the node id of the linked-to-folder which contains the ruleset(s)
*/
private String id;
public void setId(String id)
{
this.id = id;
}
public String getId()
{
return id;
}
}

View File

@@ -0,0 +1,126 @@
/*
* #%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.model.rules;
import java.util.Objects;
import java.util.StringJoiner;
import org.alfresco.rest.framework.resource.UniqueId;
import org.alfresco.service.Experimental;
@Experimental
public class RuleSetting
{
public static final String IS_INHERITANCE_ENABLED_KEY = "-isInheritanceEnabled-";
private String key;
private Object value;
@UniqueId
public String getKey()
{
return key;
}
public void setKey(String key)
{
this.key = key;
}
public Object getValue()
{
return value;
}
public void setValue(Object value)
{
this.value = value;
}
@Override
public String toString()
{
return "RuleSetting{"
+ new StringJoiner(", ")
.add("key=" + key)
.add("value=" + value.toString())
.toString()
+ "}";
}
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (!(o instanceof RuleSetting))
{
return false;
}
RuleSetting that = (RuleSetting) o;
return Objects.equals(key, that.key)
&& Objects.equals(value, that.value);
}
@Override
public int hashCode()
{
return Objects.hash(key, value);
}
public static RuleSetting.Builder builder()
{
return new RuleSetting.Builder();
}
public static class Builder
{
private String key;
private Object value;
public RuleSetting.Builder key(String key)
{
this.key = key;
return this;
}
public RuleSetting.Builder value(Object value)
{
this.value = value;
return this;
}
public RuleSetting create()
{
final RuleSetting ruleSetting = new RuleSetting();
ruleSetting.setKey(key);
ruleSetting.setValue(value);
return ruleSetting;
}
}
}

View File

@@ -31,31 +31,15 @@ import org.alfresco.service.Experimental;
@Experimental
public enum RuleTrigger
{
INBOUND("inbound"),
UPDATE("update"),
OUTBOUND("outbound");
RuleTrigger(String value)
{
this.value = value;
}
private final String value;
INBOUND, UPDATE, OUTBOUND;
public String getValue()
{
return value;
return this.name().toLowerCase();
}
public static RuleTrigger of(final String value)
{
for (RuleTrigger ruleTrigger : values())
{
if (ruleTrigger.value.equals(value)) {
return ruleTrigger;
}
}
return null;
return RuleTrigger.valueOf(value.toUpperCase());
}
}

View File

@@ -0,0 +1,277 @@
/*
* #%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.model.rules;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.alfresco.repo.action.evaluator.CompareMimeTypeEvaluator;
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator;
import org.alfresco.repo.action.evaluator.HasAspectEvaluator;
import org.alfresco.repo.action.evaluator.HasChildEvaluator;
import org.alfresco.repo.action.evaluator.HasTagEvaluator;
import org.alfresco.repo.action.evaluator.HasVersionHistoryEvaluator;
import org.alfresco.repo.action.evaluator.InCategoryEvaluator;
import org.alfresco.repo.action.evaluator.IsSubTypeEvaluator;
import org.alfresco.repo.action.evaluator.NoConditionEvaluator;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.ActionCondition;
import org.apache.commons.collections.CollectionUtils;
@Experimental
public class SimpleCondition
{
private static final String COMPARATOR_EQUALS = "equals";
private String field;
private String comparator;
private String parameter;
/**
* Converts list of service POJO action conditions to list of REST model simple conditions.
*
* @param actionConditions - list of {@link ActionCondition} service POJOs
* @return list of {@link SimpleCondition} REST models
*/
public static List<SimpleCondition> listOf(final List<ActionCondition> actionConditions)
{
if (CollectionUtils.isEmpty(actionConditions))
{
return null;
}
return actionConditions.stream()
.map(SimpleCondition::from)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
/**
* Creates simple condition REST model instance from service POJO action condition.
*
* @param actionCondition - {@link ActionCondition} service POJO
* @return {@link SimpleCondition} REST model
*/
public static SimpleCondition from(final ActionCondition actionCondition)
{
if (actionCondition == null || actionCondition.getActionConditionDefinitionName() == null || actionCondition.getParameterValues() == null)
{
return null;
}
switch (actionCondition.getActionConditionDefinitionName())
{
case ComparePropertyValueEvaluator.NAME:
return createComparePropertyValueCondition(actionCondition);
case CompareMimeTypeEvaluator.NAME:
return createCompareMimeTypeCondition(actionCondition);
case HasAspectEvaluator.NAME:
return createHasAspectCondition(actionCondition);
case HasChildEvaluator.NAME:
return createHasChildCondition(actionCondition);
case HasTagEvaluator.NAME:
return createHasTagCondition(actionCondition);
case HasVersionHistoryEvaluator.NAME:
return createHasVersionHistoryCondition(actionCondition);
case InCategoryEvaluator.NAME:
return createInCategoryCondition(actionCondition);
case IsSubTypeEvaluator.NAME:
return createIsSubtypeCondition(actionCondition);
case NoConditionEvaluator.NAME:
default:
return null;
}
}
public String getField()
{
return field;
}
public void setField(String field)
{
this.field = field;
}
public String getComparator()
{
return comparator;
}
public void setComparator(String comparator)
{
this.comparator = comparator;
}
public String getParameter()
{
return parameter;
}
public void setParameter(String parameter)
{
this.parameter = parameter;
}
@Override
public String toString()
{
return "SimpleCondition{" + "field='" + field + '\'' + ", comparator='" + comparator + '\'' + ", parameter='" + parameter + '\'' + '}';
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
SimpleCondition that = (SimpleCondition) o;
return Objects.equals(field, that.field) && Objects.equals(comparator, that.comparator) && Objects.equals(parameter, that.parameter);
}
@Override
public int hashCode()
{
return Objects.hash(field, comparator, parameter);
}
private static SimpleCondition createComparePropertyValueCondition(final ActionCondition actionCondition) {
final SimpleCondition.Builder builder = builder();
if (actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY) != null)
{
builder.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY).toString().toLowerCase());
} else {
builder.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase());
}
return builder
.comparator(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_OPERATION).toString().toLowerCase())
.parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
.create();
}
private static SimpleCondition createCompareMimeTypeCondition(final ActionCondition actionCondition) {
return builder()
.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase())
.comparator(COMPARATOR_EQUALS)
.parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
.create();
}
private static SimpleCondition createHasAspectCondition(final ActionCondition actionCondition) {
return builder()
.field(HasAspectEvaluator.PARAM_ASPECT)
.comparator(COMPARATOR_EQUALS)
.parameter(actionCondition.getParameterValues().get(HasAspectEvaluator.PARAM_ASPECT).toString())
.create();
}
private static SimpleCondition createHasChildCondition(final ActionCondition actionCondition) {
final SimpleCondition.Builder builder = builder();
if (actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_TYPE) != null)
{
builder.field(actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_TYPE).toString().toLowerCase());
} else {
builder.field(actionCondition.getParameterValues().get(HasChildEvaluator.PARAM_ASSOC_NAME).toString().toLowerCase());
}
return builder
.comparator(COMPARATOR_EQUALS)
.parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
.create();
}
private static SimpleCondition createHasTagCondition(final ActionCondition actionCondition) {
return builder()
.field(HasTagEvaluator.PARAM_TAG)
.comparator(COMPARATOR_EQUALS)
.parameter(actionCondition.getParameterValues().get(HasTagEvaluator.PARAM_TAG).toString())
.create();
}
private static SimpleCondition createHasVersionHistoryCondition(final ActionCondition actionCondition) {
return builder()
.field(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_PROPERTY).toString().toLowerCase())
.comparator(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_OPERATION).toString().toLowerCase())
.parameter(actionCondition.getParameterValues().get(ComparePropertyValueEvaluator.PARAM_VALUE).toString())
.create();
}
private static SimpleCondition createInCategoryCondition(final ActionCondition actionCondition) {
return builder()
.field(actionCondition.getParameterValues().get(InCategoryEvaluator.PARAM_CATEGORY_ASPECT).toString().toLowerCase())
.comparator(COMPARATOR_EQUALS)
.parameter(actionCondition.getParameterValues().get(InCategoryEvaluator.PARAM_CATEGORY_VALUE).toString())
.create();
}
private static SimpleCondition createIsSubtypeCondition(final ActionCondition actionCondition) {
return builder()
.field(IsSubTypeEvaluator.PARAM_TYPE)
.comparator(COMPARATOR_EQUALS)
.parameter(actionCondition.getParameterValues().get(IsSubTypeEvaluator.PARAM_TYPE).toString())
.create();
}
public static Builder builder()
{
return new Builder();
}
public static class Builder
{
private String field;
private String comparator;
private String parameter;
public Builder field(String field)
{
this.field = field;
return this;
}
public Builder comparator(String comparator)
{
this.comparator = comparator;
return this;
}
public Builder parameter(String parameter)
{
this.parameter = parameter;
return this;
}
public SimpleCondition create() {
final SimpleCondition condition = new SimpleCondition();
condition.setField(field);
condition.setComparator(comparator);
condition.setParameter(parameter);
return condition;
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* #%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.nodes;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.rest.api.RuleSets;
import org.alfresco.rest.api.model.rules.RuleSetLink;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.core.ResourceParameter;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.util.PropertyCheck;
import org.springframework.beans.factory.InitializingBean;
@RelationshipResource(name = "rule-set-links", entityResource = NodesEntityResource.class, title = "Linking to a rule set")
public class NodeRuleSetLinksRelation implements InitializingBean, RelationshipResourceAction.Create<RuleSetLink>
{
private final RuleSets ruleSets;
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "ruleSets", ruleSets);
}
@WebApiParam(name = "ruleSetLinkRequest", title = "Request body - rule set id",
description = "Request body with rule set id", kind = ResourceParameter.KIND.HTTP_BODY_OBJECT)
@WebApiDescription(title = "Link a rule set to a folder node",
description = "Submits a request to link a rule set to folder",
successStatus = HttpServletResponse.SC_CREATED)
@Override
public List<RuleSetLink> create(String nodeId, List<RuleSetLink> ruleSetLinksBody, Parameters parameters)
{
return ruleSetLinksBody.stream()
.map(r -> ruleSets.linkToRuleSet(nodeId, r.getId()))
.collect(Collectors.toList());
}
public NodeRuleSetLinksRelation(RuleSets ruleSets)
{
this.ruleSets = ruleSets;
}
}

View File

@@ -26,15 +26,84 @@
package org.alfresco.rest.api.nodes;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import org.alfresco.rest.api.RuleSets;
import org.alfresco.rest.api.model.rules.RuleSet;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.Experimental;
import org.alfresco.util.PropertyCheck;
import org.springframework.beans.factory.InitializingBean;
/**
* Folder node rule sets.
*
*/
@Experimental
@RelationshipResource(name = "rule-sets", entityResource = NodesEntityResource.class, title = "Folder node rule sets")
public class NodeRuleSetsRelation
public class NodeRuleSetsRelation implements RelationshipResourceAction.Read<RuleSet>,
RelationshipResourceAction.ReadById<RuleSet>,
InitializingBean
{
private RuleSets ruleSets;
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "ruleSets", ruleSets);
}
/**
* List rule sets for given folder.
* <p>
* - GET /nodes/{folderNodeId}/rule-sets
*
* @param folderNodeId The id of the folder node.
* @param parameters Contains paging information and information about which fields to include
* @return {@link CollectionWithPagingInfo} containing a page of rule sets
*/
@WebApiDescription (
title = "Get rule sets for a folder",
description = "Returns a paged list of rule sets for given node",
successStatus = HttpServletResponse.SC_OK
)
@Override
public CollectionWithPagingInfo<RuleSet> readAll(String folderNodeId, Parameters parameters)
{
return ruleSets.getRuleSets(folderNodeId, parameters.getInclude(), parameters.getPaging());
}
/**
* Get single folder rule for given node's, rule set's and rule's IDs.
* <p>
* - GET /nodes/{folderNodeId}/rule-sets/{ruleSetId}
*
* @param folderNodeId - entity resource context for this relationship
* @param ruleSetId - rule set node ID (associated with folder node)
* @param parameters Contains information about which fields to include
* @return {@link RuleSet} definition
* @throws RelationshipResourceNotFoundException in case resource was not found
*/
@WebApiDescription (
title = "Get rule set",
description = "Returns a single rule set for the given node",
successStatus = HttpServletResponse.SC_OK
)
@Override
public RuleSet readById(String folderNodeId, String ruleSetId, Parameters parameters) throws RelationshipResourceNotFoundException
{
return ruleSets.getRuleSetById(folderNodeId, ruleSetId, parameters.getInclude());
}
public void setRuleSets(RuleSets ruleSets)
{
this.ruleSets = ruleSets;
}
}

View File

@@ -0,0 +1,104 @@
/*
* #%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.nodes;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.rest.api.RuleSettings;
import org.alfresco.rest.api.model.rules.RuleSetting;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
import org.alfresco.rest.framework.resource.RelationshipResource;
import org.alfresco.rest.framework.resource.actions.interfaces.RelationshipResourceAction;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.Experimental;
import org.alfresco.util.PropertyCheck;
import org.springframework.beans.factory.InitializingBean;
/**
* Folder node rule settings (rule inheritance).
*/
@Experimental
@RelationshipResource (name = "rule-settings", entityResource = NodesEntityResource.class, title = "Folder rule settings")
public class NodeRuleSettingsRelation implements RelationshipResourceAction.ReadById<RuleSetting>,
RelationshipResourceAction.Update<RuleSetting>,
InitializingBean
{
private RuleSettings ruleSettings;
@Override
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "ruleSettings", ruleSettings);
}
/**
* Get the given configuration value for the specified folder.
* <p>
* - GET /nodes/{folderId}/rule-settings/{ruleSettingKey}
*
* @param folderId The id of the folder.
* @param ruleSettingKey The setting to retrieve.
* @param parameters Unused.
* @return {@link RuleSetting} The current value of the setting.
*/
@WebApiDescription (
title = "Get a folder node rule setting",
description = "Returns the specified rule setting for the given folder",
successStatus = HttpServletResponse.SC_OK
)
@Override
public RuleSetting readById(String folderId, String ruleSettingKey, Parameters parameters) throws RelationshipResourceNotFoundException
{
return ruleSettings.getRuleSetting(folderId, ruleSettingKey);
}
/**
* Set the value of a rule setting for the specified folder.
* <p>
* PUT /nodes/{folderId}/rule-settings/{ruleSettingKey}
*
* @param folderId The id of the folder.
* @param ruleSetting The new value of the rule setting.
* @param parameters Unused.
* @return The updated rule setting.
*/
@WebApiDescription (
title = "Update folder node rule setting",
description = "Update a rule setting for given node",
successStatus = HttpServletResponse.SC_OK
)
@Override
public RuleSetting update(String folderId, RuleSetting ruleSetting, Parameters parameters)
{
return ruleSettings.setRuleSetting(folderId, ruleSetting);
}
public void setRuleSettings(RuleSettings ruleSettings)
{
this.ruleSettings = ruleSettings;
}
}

View File

@@ -26,6 +26,9 @@
package org.alfresco.rest.api.nodes;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import org.alfresco.rest.api.Rules;
import org.alfresco.rest.api.model.rules.Rule;
import org.alfresco.rest.framework.WebApiDescription;
@@ -38,9 +41,6 @@ import org.alfresco.service.Experimental;
import org.alfresco.util.PropertyCheck;
import org.springframework.beans.factory.InitializingBean;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* Folder node's rules.
*
@@ -82,7 +82,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
{
final String ruleSetId = parameters.getRelationshipId();
return rules.getRules(folderNodeId, ruleSetId, parameters.getPaging());
return rules.getRules(folderNodeId, ruleSetId, parameters.getInclude(), parameters.getPaging());
}
/**
@@ -106,7 +106,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
{
final String ruleId = parameters.getRelationship2Id();
return rules.getRuleById(folderNodeId, ruleSetId, ruleId);
return rules.getRuleById(folderNodeId, ruleSetId, ruleId, parameters.getInclude());
}
/**
@@ -129,7 +129,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
{
final String ruleSetId = parameters.getRelationshipId();
return rules.createRules(folderNodeId, ruleSetId, ruleList);
return rules.createRules(folderNodeId, ruleSetId, ruleList, parameters.getInclude());
}
/**
@@ -153,7 +153,7 @@ public class NodeRulesRelation implements RelationshipResourceAction.Read<Rule>,
{
String ruleSetId = parameters.getRelationshipId();
String ruleId = parameters.getRelationship2Id();
return rules.updateRuleById(folderNodeId, ruleSetId, ruleId, rule);
return rules.updateRuleById(folderNodeId, ruleSetId, ruleId, rule, parameters.getInclude());
}
/**

View File

@@ -121,8 +121,8 @@ public class ResourceLookupDictionary implements ResourceLocator
return resource;
}
}
logger.warn("Unable to locate resource resource for :"+entityResource+" "+relationResource==null?"":relationResource+" "+property==null?"":property);
throw new NotFoundException("Unable to locate resource resource for :"+entityResource+" "+(relationResource==null?"":relationResource+" "+property==null?"":property));
logger.warn("Unable to locate resource for: "+entityResource+" "+relationResource==null ? "" : relationResource+" "+property==null ? "" : property);
throw new NotFoundException("Unable to locate resource for: "+entityResource+" "+(relationResource==null ? "" : relationResource+" "+property==null ? "" : property));
}
else
{
@@ -160,8 +160,8 @@ public class ResourceLookupDictionary implements ResourceLocator
return resource;
}
}
logger.warn("Unable to locate resource resource for :"+entityResource+" "+relationResource==null?"":relationResource);
throw new NotFoundException("Unable to locate resource resource for :"+entityResource+" "+(relationResource==null?"":relationResource));
logger.warn("Unable to locate resource for: "+entityResource+" "+relationResource==null ? "" : relationResource);
throw new NotFoundException("Unable to locate resource for: "+entityResource+" "+relationResource==null ? "" : relationResource);
}
else
{

View File

@@ -850,10 +850,65 @@
</property>
</bean>
<bean id="rules" class="org.alfresco.rest.api.impl.RulesImpl">
<bean id="nodeValidator" class="org.alfresco.rest.api.impl.rules.NodeValidator">
<property name="nodes" ref="Nodes" />
<property name="permissionService" ref="PermissionService"/>
<property name="permissionService" ref="PermissionService" />
<property name="ruleService" ref="RuleService" />
<property name="nodeService" ref="NodeService"/>
</bean>
<bean class="org.alfresco.rest.api.nodes.NodeRulesRelation">
<property name="rules" ref="Rules" />
</bean>
<bean id="ruleSetLoader" class="org.alfresco.rest.api.impl.rules.RuleSetLoader">
<property name="nodeService" ref="NodeService" />
</bean>
<bean id="ruleSets" class="org.alfresco.rest.api.impl.rules.RuleSetsImpl">
<property name="ruleSetLoader" ref="ruleSetLoader" />
<property name="validator" ref="nodeValidator" />
<property name="ruleService" ref="RuleService" />
<property name="nodeService" ref="NodeService"/>
<property name="runtimeRuleService" ref="ruleService"/>
</bean>
<bean id="RuleSets" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="org.alfresco.rest.api.RuleSets" />
<property name="target" ref="ruleSets" />
<property name="interceptorNames">
<list>
<idref bean="legacyExceptionInterceptor" />
</list>
</property>
</bean>
<bean id="ruleLoader" class="org.alfresco.rest.api.impl.rules.RuleLoader">
<property name="ruleService" ref="RuleService" />
<property name="nodeValidator" ref="nodeValidator" />
</bean>
<bean class="org.alfresco.rest.api.nodes.NodeRuleSetsRelation">
<property name="ruleSets" ref="RuleSets" />
</bean>
<bean id="actionParameterConverter" class="org.alfresco.rest.api.impl.rules.ActionParameterConverter">
<constructor-arg name="actionService" ref="ActionService"/>
<constructor-arg name="dictionaryService" ref="DictionaryService"/>
<constructor-arg name="namespaceService" ref="NamespaceService"/>
</bean>
<bean id="actionPermissionValidator" class="org.alfresco.rest.api.impl.rules.ActionPermissionValidator">
<constructor-arg name="runtimeActionService" ref="actionService"/>
</bean>
<bean id="rules" class="org.alfresco.rest.api.impl.rules.RulesImpl">
<property name="nodes" ref="Nodes" />
<property name="validator" ref="nodeValidator"/>
<property name="ruleService" ref="RuleService" />
<property name="ruleLoader" ref="ruleLoader"/>
<property name="actionParameterConverter" ref="actionParameterConverter"/>
<property name="actionPermissionValidator" ref="actionPermissionValidator"/>
</bean>
<bean id="Rules" class="org.springframework.aop.framework.ProxyFactoryBean">
@@ -866,8 +921,27 @@
</property>
</bean>
<bean class="org.alfresco.rest.api.nodes.NodeRulesRelation">
<property name="rules" ref="Rules" />
<bean class="org.alfresco.rest.api.nodes.NodeRuleSetLinksRelation">
<constructor-arg name="ruleSets" ref="RuleSets" />
</bean>
<bean id="ruleSettings" class="org.alfresco.rest.api.impl.rules.RuleSettingsImpl">
<property name="validator" ref="nodeValidator" />
<property name="nodeService" ref="NodeService" />
</bean>
<bean id="RuleSettings" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="org.alfresco.rest.api.RuleSettings" />
<property name="target" ref="ruleSettings" />
<property name="interceptorNames">
<list>
<idref bean="legacyExceptionInterceptor" />
</list>
</property>
</bean>
<bean class="org.alfresco.rest.api.nodes.NodeRuleSettingsRelation">
<property name="ruleSettings" ref="RuleSettings" />
</bean>
<bean id="publicapi.mimeTypePropertyLookup" class="org.alfresco.rest.api.lookups.MimeTypePropertyLookup">

View File

@@ -249,6 +249,7 @@
<property name="delegate" ref="webscript.content.streamer" />
<property name="contentService" ref="contentService" />
<property name="repository" ref="repositoryHelper" />
<property name="nonAttachContentTypes" value="#{T(java.util.Arrays).asList('${content.nonAttach.mimetypes}')}" />
</bean>
<!-- Content Info -->

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Share Services AMP
* %%
* 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
@@ -66,13 +66,17 @@ public class ContentGetTest extends BaseWebScriptTest
{
super.setUp();
this.authenticationService = (MutableAuthenticationService) getServer().getApplicationContext()
.getBean("AuthenticationService");
this.authenticationService = (MutableAuthenticationService)getServer().getApplicationContext().getBean("AuthenticationService");
this.personService = (PersonService) getServer().getApplicationContext().getBean("PersonService");
this.nodeService = (NodeService) getServer().getApplicationContext().getBean("NodeService");
this.contentService = (ContentService) getServer().getApplicationContext().getBean("ContentService");
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
createUser(USER_ONE);
Repository repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper");
NodeRef companyHome = repositoryHelper.getCompanyHome();
rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER);
}
private void createUser(String userName)
@@ -117,18 +121,13 @@ public class ContentGetTest extends BaseWebScriptTest
*/
public void testRelativePath() throws Exception
{
Repository repositoryHelper = (Repository) getServer().getApplicationContext().getBean("repositoryHelper");
NodeRef companyHome = repositoryHelper.getCompanyHome();
rootFolder = createNode(companyHome, "rootFolder", ContentModel.TYPE_FOLDER);
NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content");
NodeRef doc1 = createNodeWithTextContent(rootFolder, "doc1", ContentModel.TYPE_CONTENT, "doc1 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN);
NodeRef folderX = createNode(rootFolder, "X", ContentModel.TYPE_FOLDER);
NodeRef folderY = createNode(folderX, "Y", ContentModel.TYPE_FOLDER);
NodeRef folderZ = createNode(folderY, "Z", ContentModel.TYPE_FOLDER);
NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content");
NodeRef doc2 = createNodeWithTextContent(folderZ, "doc2", ContentModel.TYPE_CONTENT, "doc2 file content", MimetypeMap.MIMETYPE_TEXT_PLAIN);
// uri with relative path at the end
String uri = URL_CONTENT_DOWNLOAD + doc1.getId() + "/X/Y/Z/doc2";
@@ -138,7 +137,46 @@ public class ContentGetTest extends BaseWebScriptTest
Assert.assertEquals("doc2 file content", resp.getContentAsString());
}
public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content)
public void testForcedAttachment() throws Exception
{
NodeRef testhtml = createNodeWithTextContent(rootFolder, "testhtml", ContentModel.TYPE_CONTENT, "testhtml content", MimetypeMap.MIMETYPE_HTML);
NodeRef testpdf = createNodeWithTextContent(rootFolder, "testpdf", ContentModel.TYPE_CONTENT, "testpdf content", MimetypeMap.MIMETYPE_PDF);
String uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=false";
GetRequest req = new GetRequest(uri);
Response res = sendRequest(req, 200);
assertEquals("attachment", res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
uri = URL_CONTENT_DOWNLOAD + testhtml.getId();
res = sendRequest(new GetRequest(uri), 200);
assertEquals("attachment", res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
uri = URL_CONTENT_DOWNLOAD + testhtml.getId() + "?a=true";
res = sendRequest(new GetRequest(uri), 200);
assertEquals("attachment", res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_HTML + ";charset=UTF-8", res.getContentType());
uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=false";
res = sendRequest(new GetRequest(uri), 200);
assertNull(res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
uri = URL_CONTENT_DOWNLOAD + testpdf.getId();
res = sendRequest(new GetRequest(uri), 200);
assertNull(res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
uri = URL_CONTENT_DOWNLOAD + testpdf.getId() + "?a=true";
res = sendRequest(new GetRequest(uri), 200);
assertEquals("attachment", res.getHeader("Content-Disposition"));
assertEquals(MimetypeMap.MIMETYPE_PDF + ";charset=UTF-8", res.getContentType());
}
public NodeRef createNodeWithTextContent(NodeRef parentNode, String nodeCmName, QName nodeType, String content, String mimetype)
{
NodeRef nodeRef = createNode(parentNode, nodeCmName, nodeType);
@@ -146,7 +184,7 @@ public class ContentGetTest extends BaseWebScriptTest
if (content != null)
{
ContentWriter writer = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
writer.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
writer.setMimetype(mimetype);
writer.setEncoding("UTF-8");
writer.putContent(content);
}

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco 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.repo.web.util;
import java.io.BufferedReader;
@@ -32,6 +32,7 @@ import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Arrays;
import java.util.Date;
import javax.servlet.ServletContext;
@@ -44,7 +45,8 @@ import org.alfresco.util.TempFileProvider;
import org.alfresco.util.WebApplicationContextLoader;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.http.UriCompliance;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.springframework.beans.BeanUtils;
@@ -145,6 +147,8 @@ public abstract class AbstractJettyComponent implements JettyComponent
configureWebAppContext(webAppContext);
ignoreAmbiguousLinks(server);
server.start();
if(logger.isDebugEnabled())
@@ -203,15 +207,27 @@ public abstract class AbstractJettyComponent implements JettyComponent
}
}
});
// with a login-config in web.xml, jetty seems to require this in order to start successfully
webAppContext.getSecurityHandler().setLoginService(new HashLoginService());
// arbitrary temporary file location
File tmp = new File(TempFileProvider.getSystemTempDir(), String.valueOf(System.currentTimeMillis()));
webAppContext.setResourceBase(tmp.getAbsolutePath());
}
/**
* In newer jetty versions there is a stricter check for links e.g. "//" is not allowed, which clashes
* with some of our tests, because even a NodeRef triggers it - "workspace://..."
* Since Jetty is only used in tests it's alright to block this behaviour.
*
* @param server
*/
private void ignoreAmbiguousLinks(Server server) {
Arrays.stream(server.getConnectors())
.flatMap(c -> c.getConnectionFactories().stream())
.filter(cf -> cf instanceof HttpConnectionFactory)
.map(cf -> (HttpConnectionFactory) cf)
.forEach(hcf -> hcf.getHttpConfiguration().setUriCompliance(UriCompliance.RFC3986));
}
public void shutdown()
{
try

View File

@@ -26,8 +26,13 @@
package org.alfresco.rest.api;
import org.alfresco.rest.api.impl.RulesImplTest;
import org.alfresco.rest.api.impl.rules.NodeValidatorTest;
import org.alfresco.rest.api.impl.rules.RuleSetsImplTest;
import org.alfresco.rest.api.model.rules.ActionTest;
import org.alfresco.rest.api.model.rules.CompositeConditionTest;
import org.alfresco.rest.api.impl.rules.RulesImplTest;
import org.alfresco.rest.api.model.rules.RuleTest;
import org.alfresco.rest.api.model.rules.SimpleConditionTest;
import org.alfresco.rest.api.nodes.NodeRulesRelationTest;
import org.alfresco.service.Experimental;
import org.junit.runner.RunWith;
@@ -38,7 +43,12 @@ import org.junit.runners.Suite;
@Suite.SuiteClasses({
NodeRulesRelationTest.class,
RulesImplTest.class,
RuleTest.class
RuleSetsImplTest.class,
NodeValidatorTest.class,
RuleTest.class,
ActionTest.class,
SimpleConditionTest.class,
CompositeConditionTest.class
})
public class RulesUnitTests
{

View File

@@ -1,579 +0,0 @@
/*
* #%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.impl;
import static java.util.Collections.emptyList;
import static org.alfresco.rest.api.model.rules.RuleSet.DEFAULT_ID;
import static org.alfresco.service.cmr.security.AccessStatus.ALLOWED;
import static org.alfresco.service.cmr.security.AccessStatus.DENIED;
import static org.alfresco.service.cmr.security.PermissionService.CHANGE_PERMISSIONS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import junit.framework.TestCase;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.rules.Rule;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.security.PermissionService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
@Experimental
@RunWith(MockitoJUnitRunner.class)
public class RulesImplTest extends TestCase
{
private static final String FOLDER_NODE_ID = "dummy-folder-node-id";
private static final String RULE_SET_ID = "dummy-rule-set-id";
private static final String RULE_ID = "dummy-rule-id";
private static final NodeRef folderNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID);
private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
private static final NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID);
private static final Paging paging = Paging.DEFAULT;
private static final Action action = new ActionImpl(folderNodeRef, "actionId", "actionDefinitionName");
private static final String RULE_NAME = "Rule name";
@Mock
private Nodes nodesMock;
@Mock
private PermissionService permissionServiceMock;
@Mock
private RuleService ruleServiceMock;
@InjectMocks
private RulesImpl rules;
@Before
@Override
public void setUp() throws Exception
{
MockitoAnnotations.openMocks(this);
given(nodesMock.validateOrLookupNode(eq(FOLDER_NODE_ID), any())).willReturn(folderNodeRef);
given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
given(nodesMock.nodeMatches(any(), any(), any())).willReturn(true);
given(permissionServiceMock.hasReadPermission(any())).willReturn(ALLOWED);
given(permissionServiceMock.hasPermission(any(), any())).willReturn(ALLOWED);
}
@Test
public void testGetRules()
{
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
given(ruleServiceMock.getRules(any())).willReturn(List.of(createRule(RULE_ID)));
// when
final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging);
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().validateNode(RULE_SET_ID);
then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().getRules(folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rulesPage)
.isNotNull()
.extracting(CollectionWithPagingInfo::getCollection)
.isNotNull()
.extracting(Collection::size)
.isEqualTo(1);
assertThat(rulesPage.getCollection().stream().findFirst().orElse(null))
.isNotNull()
.extracting(Rule::getId)
.isEqualTo(RULE_ID);
}
@Test
public void testGetRulesForDefaultRuleSet()
{
given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef);
given(ruleServiceMock.getRules(any())).willReturn(List.of(createRule(RULE_ID)));
// when
final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, DEFAULT_ID, paging);
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().getRules(folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rulesPage)
.isNotNull()
.extracting(CollectionWithPagingInfo::getCollection)
.isNotNull()
.extracting(Collection::size)
.isEqualTo(1);
assertThat(rulesPage.getCollection().stream().findFirst().orElse(null))
.isNotNull()
.extracting(Rule::getId)
.isEqualTo(RULE_ID);
}
@Test
public void testGetRulesForNotExistingFolderNode()
{
given(nodesMock.nodeMatches(eq(folderNodeRef), any(), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
then(ruleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testGetRulesForNotExistingRuleSetNode()
{
given(nodesMock.nodeMatches(eq(folderNodeRef), any(), any())).willReturn(true);
given(nodesMock.nodeMatches(eq(ruleSetNodeRef), any(), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
then(ruleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testGetRulesForNotAssociatedRuleSetToFolder()
{
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testGetRulesWithoutReadPermission()
{
given(permissionServiceMock.hasReadPermission(any())).willReturn(DENIED);
// when
assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(
() -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, paging));
then(ruleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testGetRuleById()
{
given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true);
given(ruleServiceMock.getRule(any())).willReturn(createRule(RULE_ID));
// when
final Rule rule = rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID);
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().validateNode(RULE_SET_ID);
then(nodesMock).should().validateNode(RULE_ID);
then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull());
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().getRule(ruleNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rule)
.isNotNull()
.extracting(Rule::getId)
.isEqualTo(RULE_ID);
}
@Test
public void testGetRuleByIdForDefaultRuleSet()
{
final String defaultRuleSetId = "-default-";
given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef);
given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true);
given(ruleServiceMock.getRule(any())).willReturn(createRule(RULE_ID));
// when
final Rule rule = rules.getRuleById(FOLDER_NODE_ID, defaultRuleSetId, RULE_ID);
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().validateNode(RULE_ID);
then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull());
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().getRule(ruleNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rule)
.isNotNull()
.extracting(Rule::getId)
.isEqualTo(RULE_ID);
}
@Test
public void testGetRuleByIdForNotAssociatedRuleToRuleSet()
{
given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
/** Create a single rule. */
@Test
public void testSaveRules()
{
Rule ruleBody = mock(Rule.class);
List<Rule> ruleList = List.of(ruleBody);
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody);
org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule);
given(serviceRule.getNodeRef()).willReturn(ruleNodeRef);
given(serviceRule.getAction()).willReturn(action);
// when
List<Rule> actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList);
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock));
then(ruleServiceMock).shouldHaveNoMoreInteractions();
List<Rule> expected = List.of(Rule.from(serviceRule, false));
assertThat(actual).isEqualTo(expected);
}
/** Check that when passing the default rule set then we don't perform any validation around the rule set node. */
@Test
public void testSaveRules_defaultRuleSet()
{
Rule ruleBody = mock(Rule.class);
List<Rule> ruleList = List.of(ruleBody);
org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody);
given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef);
org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule);
given(serviceRule.getNodeRef()).willReturn(ruleNodeRef);
given(serviceRule.getAction()).willReturn(action);
// when
List<Rule> actual = rules.createRules(folderNodeRef.getId(), DEFAULT_ID, ruleList);
then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock));
then(ruleServiceMock).shouldHaveNoMoreInteractions();
List<Rule> expected = List.of(Rule.from(serviceRule, false));
assertThat(actual).isEqualTo(expected);
}
@Test
public void testSaveRules_ruleSetNotAssociatedWithFolder()
{
Rule rule = Rule.builder().name(RULE_NAME).create();
List<Rule> ruleList = List.of(rule);
given(ruleServiceMock.isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef)).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList));
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testSaveRules_emptyRuleList()
{
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
List<Rule> ruleList = emptyList();
// when
List<Rule> actual = this.rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList);
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(actual).isEqualTo(emptyList());
}
/** Create three rules in a single call and check they are all passed to the RuleService. */
@Test
public void testSaveRules_createMultipleRules()
{
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
List<Rule> ruleBodyList = new ArrayList<>();
List<Rule> expected = new ArrayList<>();
for (String ruleId : List.of("A", "B", "C"))
{
Rule ruleBody = mock(Rule.class);
ruleBodyList.add(ruleBody);
org.alfresco.service.cmr.rule.Rule serviceRuleBody = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleBody.toServiceModel(nodesMock)).willReturn(serviceRuleBody);
org.alfresco.service.cmr.rule.Rule serviceRule = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleServiceMock.saveRule(folderNodeRef, serviceRuleBody)).willReturn(serviceRule);
NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, ruleId);
given(serviceRule.getNodeRef()).willReturn(ruleNodeRef);
given(serviceRule.getAction()).willReturn(action);
expected.add(Rule.from(serviceRule, false));
}
// when
List<Rule> actual = rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleBodyList);
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
for (Rule ruleBody : ruleBodyList)
{
then(ruleServiceMock).should().saveRule(folderNodeRef, ruleBody.toServiceModel(nodesMock));
}
then(ruleServiceMock).should(times(ruleBodyList.size())).isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(actual).isEqualTo(expected);
}
/** Try to create a rule without CHANGE permission and check an exception is thrown. */
@Test
public void testSaveRules_noChangePermission()
{
given(permissionServiceMock.hasPermission(folderNodeRef, CHANGE_PERMISSIONS)).willReturn(DENIED);
Rule ruleBody = mock(Rule.class);
List<Rule> ruleList = List.of(ruleBody);
// when
assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(() ->
rules.createRules(folderNodeRef.getId(), ruleSetNodeRef.getId(), ruleList));
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testDeleteRuleById() {
given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true);
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
org.alfresco.service.cmr.rule.Rule rule = createRule(RULE_ID);
given(ruleServiceMock.getRule(any())).willReturn(rule);
//when
rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID);
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().validateNode(RULE_SET_ID);
then(nodesMock).should().validateNode(RULE_ID);
then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull());
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
then(ruleServiceMock).should().getRule(ruleNodeRef);
then(ruleServiceMock).should().removeRule(folderNodeRef, rule);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testDeleteRuleById_NonExistingRuleId() {
given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
given(nodesMock.validateNode(RULE_ID)).willThrow(new EntityNotFoundException(RULE_ID));
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
//when
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
() -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().validateNode(RULE_SET_ID);
then(nodesMock).should().validateNode(RULE_ID);
then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testDeleteRuleById_RuleIdNotInRuleSet() {
given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(false);
//when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().validateNode(RULE_SET_ID);
then(nodesMock).should().validateNode(RULE_ID);
then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
then(nodesMock).should().nodeMatches(eq(ruleNodeRef), any(), isNull());
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testDeleteRuleById_NonExistingRuleSetId() {
given(nodesMock.validateNode(RULE_SET_ID)).willThrow(new EntityNotFoundException(RULE_SET_ID));
//when
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
() -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().validateNode(RULE_SET_ID);
then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testDeleteRuleById_RuleSetNotInFolder() {
given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(false);
//when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().validateNode(RULE_SET_ID);
then(nodesMock).should().nodeMatches(eq(folderNodeRef), any(), isNull());
then(nodesMock).should().nodeMatches(eq(ruleSetNodeRef), any(), isNull());
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testDeleteRuleById_NonExistingFolderId() {
given(nodesMock.validateOrLookupNode(FOLDER_NODE_ID, null)).willThrow(new EntityNotFoundException(RULE_ID));
//when
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
() -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
/** Try to delete a rule without CHANGE permission and check an exception is thrown. */
@Test
public void testDeleteRuleById_noChangePermission()
{
given(permissionServiceMock.hasPermission(folderNodeRef, CHANGE_PERMISSIONS)).willReturn(DENIED);
// when
assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(() ->
rules.deleteRuleById(folderNodeRef.getId(), ruleSetNodeRef.getId(), RULE_ID));
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
private static org.alfresco.service.cmr.rule.Rule createRule(final String id) {
final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id);
final org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
rule.setNodeRef(nodeRef);
rule.setRuleType("ruleType");
rule.setAction(action);
return rule;
}
}

View File

@@ -0,0 +1,592 @@
/*
* #%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.impl.rules;
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.times;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.action.executer.AddFeaturesActionExecuter;
import org.alfresco.repo.action.executer.CheckInActionExecuter;
import org.alfresco.repo.action.executer.CheckOutActionExecuter;
import org.alfresco.repo.action.executer.CopyActionExecuter;
import org.alfresco.repo.action.executer.LinkCategoryActionExecuter;
import org.alfresco.repo.action.executer.MoveActionExecuter;
import org.alfresco.repo.action.executer.RemoveFeaturesActionExecuter;
import org.alfresco.repo.action.executer.ScriptActionExecuter;
import org.alfresco.repo.action.executer.SetPropertyValueActionExecuter;
import org.alfresco.repo.action.executer.SimpleWorkflowActionExecuter;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.ActionDefinition;
import org.alfresco.service.cmr.action.ActionService;
import org.alfresco.service.cmr.action.ParameterDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@Experimental
@RunWith(MockitoJUnitRunner.class)
public class ActionParameterConverterTest
{
private static final String VERSIONABLE = "versionable";
private static final String VERSIONABLE_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + VERSIONABLE;
private static final String CHECKOUT = "checkout";
private static final String CHECKOUT_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + CHECKOUT;
private static final String CONTAINS = "contains";
private static final String CONTAINS_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + CONTAINS;
private static final String CLASSIFIABLE = "generalclassifiable";
private static final String CLASSIFIABLE_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + CLASSIFIABLE;
private static final String IDENTIFIER = "identifier";
private static final String IDENTIFIER_ASPECT = NamespaceService.CONTENT_MODEL_PREFIX + QName.NAMESPACE_PREFIX + IDENTIFIER;
private static final String DUMMY_FOLDER_NODE_ID = "dummy-folder-node";
private static final String DUMMY_SCRIPT_NODE_ID = "dummy-script-ref";
@Mock
private DictionaryService dictionaryService;
@Mock
private ActionService actionService;
@Mock
private NamespaceService namespaceService;
@Mock
private ActionDefinition actionDefinition;
@Mock
private ParameterDefinition actionDefinitionParam1;
@Mock
private ParameterDefinition actionDefinitionParam2;
@Mock
private ParameterDefinition actionDefinitionParam3;
@Mock
private DataTypeDefinition dataTypeDefinition1;
@Mock
private DataTypeDefinition dataTypeDefinition2;
@Mock
private DataTypeDefinition dataTypeDefinition3;
@InjectMocks
private ActionParameterConverter objectUnderTest;
@Test
public void testAddAspectConversion()
{
final String name = AddFeaturesActionExecuter.NAME;
final String aspectNameKey = AddFeaturesActionExecuter.PARAM_ASPECT_NAME;
final Map<String, Serializable> params = Map.of(aspectNameKey, VERSIONABLE_ASPECT);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(aspectNameKey)).willReturn(actionDefinitionParam1);
final QName qname = DataTypeDefinition.QNAME;
given(actionDefinitionParam1.getType()).willReturn(qname);
given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition1);
given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
then(actionService).should().getActionDefinition(name);
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(aspectNameKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should().getDataType(qname);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).should().getNamespaceURI(any());
then(namespaceService).shouldHaveNoMoreInteractions();
final Serializable convertedParam = convertedParams.get(aspectNameKey);
assertTrue(convertedParam instanceof QName);
assertEquals(VERSIONABLE, ((QName) convertedParam).getLocalName());
assertEquals(VERSIONABLE_ASPECT, ((QName) convertedParam).getPrefixString());
assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedParam).getNamespaceURI());
}
@Test
public void testCopyConversion()
{
final String name = CopyActionExecuter.NAME;
final String destinationFolderKey = CopyActionExecuter.PARAM_DESTINATION_FOLDER;
final String deepCopyKey = CopyActionExecuter.PARAM_DEEP_COPY;
final Map<String, Serializable> params = Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_ID, deepCopyKey, true);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(destinationFolderKey)).willReturn(actionDefinitionParam1);
given(actionDefinition.getParameterDefintion(deepCopyKey)).willReturn(actionDefinitionParam2);
final QName nodeRef = DataTypeDefinition.NODE_REF;
given(actionDefinitionParam1.getType()).willReturn(nodeRef);
final QName bool = DataTypeDefinition.BOOLEAN;
given(actionDefinitionParam2.getType()).willReturn(bool);
given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
given(dictionaryService.getDataType(bool)).willReturn(dataTypeDefinition2);
given(dataTypeDefinition2.getJavaClassName()).willReturn(Boolean.class.getName());
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
then(actionService).should().getActionDefinition(name);
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(destinationFolderKey);
then(actionDefinition).should().getParameterDefintion(deepCopyKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should(times(2)).getDataType(bool);
then(dictionaryService).should().getDataType(nodeRef);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).shouldHaveNoInteractions();
final Serializable convertedCopyParam = convertedParams.get(destinationFolderKey);
assertTrue(convertedCopyParam instanceof NodeRef);
assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedCopyParam).getStoreRef());
assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedCopyParam).getId());
final Serializable convertedDeepCopyParam = convertedParams.get(deepCopyKey);
assertThat(convertedDeepCopyParam instanceof Boolean).isTrue();
assertTrue(((Boolean) convertedDeepCopyParam));
}
@Test
public void testExecuteScriptConversion()
{
final String name = ScriptActionExecuter.NAME;
final String executeScriptKey = ScriptActionExecuter.PARAM_SCRIPTREF;
final Map<String, Serializable> params = Map.of(executeScriptKey, DUMMY_SCRIPT_NODE_ID);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(executeScriptKey)).willReturn(actionDefinitionParam1);
final QName scriptNodeRef = DataTypeDefinition.NODE_REF;
given(actionDefinitionParam1.getType()).willReturn(scriptNodeRef);
given(dictionaryService.getDataType(scriptNodeRef)).willReturn(dataTypeDefinition1);
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
then(actionService).should().getActionDefinition(name);
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(executeScriptKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should().getDataType(scriptNodeRef);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).shouldHaveNoInteractions();
final Serializable convertedCopyParam = convertedParams.get(executeScriptKey);
assertTrue(convertedCopyParam instanceof NodeRef);
assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedCopyParam).getStoreRef());
assertEquals(DUMMY_SCRIPT_NODE_ID, ((NodeRef) convertedCopyParam).getId());
}
@Test
public void testMoveConversion()
{
final String name = MoveActionExecuter.NAME;
final String destinationFolderKey = MoveActionExecuter.PARAM_DESTINATION_FOLDER;
final Map<String, Serializable> params = Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_ID);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(destinationFolderKey)).willReturn(actionDefinitionParam1);
final QName nodeRef = DataTypeDefinition.NODE_REF;
given(actionDefinitionParam1.getType()).willReturn(nodeRef);
given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
then(actionService).should().getActionDefinition(name);
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(destinationFolderKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should().getDataType(nodeRef);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).shouldHaveNoInteractions();
final Serializable convertedCopyParam = convertedParams.get(destinationFolderKey);
assertTrue(convertedCopyParam instanceof NodeRef);
assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedCopyParam).getStoreRef());
assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedCopyParam).getId());
}
@Test
public void testCheckInConversion()
{
final String name = CheckInActionExecuter.NAME;
final String descriptionKey = CheckInActionExecuter.PARAM_DESCRIPTION;
final String minorChangeKey = CheckInActionExecuter.PARAM_MINOR_CHANGE;
String description = "dummy description";
final Map<String, Serializable> params = Map.of(descriptionKey, description, minorChangeKey, true);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(descriptionKey)).willReturn(actionDefinitionParam1);
given(actionDefinition.getParameterDefintion(minorChangeKey)).willReturn(actionDefinitionParam2);
final QName text = DataTypeDefinition.TEXT;
given(actionDefinitionParam1.getType()).willReturn(text);
final QName bool = DataTypeDefinition.BOOLEAN;
given(actionDefinitionParam2.getType()).willReturn(bool);
given(dictionaryService.getDataType(text)).willReturn(dataTypeDefinition1);
given(dataTypeDefinition1.getJavaClassName()).willReturn(String.class.getName());
given(dictionaryService.getDataType(bool)).willReturn(dataTypeDefinition2);
given(dataTypeDefinition2.getJavaClassName()).willReturn(Boolean.class.getName());
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
then(actionService).should().getActionDefinition(name);
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(descriptionKey);
then(actionDefinition).should().getParameterDefintion(minorChangeKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should(times(2)).getDataType(bool);
then(dictionaryService).should(times(2)).getDataType(text);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).shouldHaveNoInteractions();
final Serializable convertedDescriptionParam = convertedParams.get(descriptionKey);
assertTrue(convertedDescriptionParam instanceof String);
assertEquals(description, convertedDescriptionParam);
final Serializable convertedMinorChangeParam = convertedParams.get(minorChangeKey);
assertTrue(convertedMinorChangeParam instanceof Boolean);
assertTrue((Boolean) convertedMinorChangeParam);
}
@Test
public void testCheckOutConversion()
{
final String name = CheckOutActionExecuter.NAME;
final String destinationFolderKey = CheckOutActionExecuter.PARAM_DESTINATION_FOLDER;
final String assocNameKey = CheckOutActionExecuter.PARAM_ASSOC_QNAME;
final String assocTypeKey = CheckOutActionExecuter.PARAM_ASSOC_TYPE_QNAME;
final Map<String, Serializable> params =
Map.of(destinationFolderKey, DUMMY_FOLDER_NODE_ID, assocNameKey, CHECKOUT_ASPECT, assocTypeKey, CONTAINS_ASPECT);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(destinationFolderKey)).willReturn(actionDefinitionParam1);
final QName nodeRef = DataTypeDefinition.NODE_REF;
given(actionDefinitionParam1.getType()).willReturn(nodeRef);
given(actionDefinition.getParameterDefintion(assocNameKey)).willReturn(actionDefinitionParam2);
final QName qname = DataTypeDefinition.QNAME;
given(actionDefinitionParam2.getType()).willReturn(qname);
given(actionDefinition.getParameterDefintion(assocTypeKey)).willReturn(actionDefinitionParam3);
given(actionDefinitionParam3.getType()).willReturn(qname);
given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition2);
given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
then(actionService).should().getActionDefinition(name);
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(destinationFolderKey);
then(actionDefinition).should().getParameterDefintion(assocNameKey);
then(actionDefinition).should().getParameterDefintion(assocTypeKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should(times(2)).getDataType(qname);
then(dictionaryService).should().getDataType(nodeRef);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).should(times(2)).getNamespaceURI(any());
then(namespaceService).shouldHaveNoMoreInteractions();
final Serializable convertedDestinationParam = convertedParams.get(destinationFolderKey);
assertTrue(convertedDestinationParam instanceof NodeRef);
assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedDestinationParam).getStoreRef());
assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedDestinationParam).getId());
final Serializable convertedAssocNameParam = convertedParams.get(assocNameKey);
assertTrue(convertedAssocNameParam instanceof QName);
assertEquals(CHECKOUT, ((QName) convertedAssocNameParam).getLocalName());
assertEquals(CHECKOUT_ASPECT, ((QName) convertedAssocNameParam).getPrefixString());
assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedAssocNameParam).getNamespaceURI());
final Serializable convertedAssocTypeParam = convertedParams.get(assocTypeKey);
assertTrue(convertedAssocTypeParam instanceof QName);
assertEquals(CONTAINS, ((QName) convertedAssocTypeParam).getLocalName());
assertEquals(CONTAINS_ASPECT, ((QName) convertedAssocTypeParam).getPrefixString());
assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedAssocTypeParam).getNamespaceURI());
}
@Test
public void testCategoryLinkConversion()
{
final String name = LinkCategoryActionExecuter.NAME;
final String categoryAspectKey = LinkCategoryActionExecuter.PARAM_CATEGORY_ASPECT;
final String categoryValueKey = LinkCategoryActionExecuter.PARAM_CATEGORY_VALUE;
final Map<String, Serializable> params = Map.of(categoryAspectKey, CLASSIFIABLE_ASPECT, categoryValueKey, DUMMY_FOLDER_NODE_ID);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(categoryAspectKey)).willReturn(actionDefinitionParam1);
final QName qname = DataTypeDefinition.QNAME;
given(actionDefinitionParam1.getType()).willReturn(qname);
given(actionDefinition.getParameterDefintion(categoryValueKey)).willReturn(actionDefinitionParam2);
final QName nodeRef = DataTypeDefinition.NODE_REF;
given(actionDefinitionParam2.getType()).willReturn(nodeRef);
given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition2);
given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
then(actionService).should().getActionDefinition(name);
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(categoryAspectKey);
then(actionDefinition).should().getParameterDefintion(categoryValueKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should().getDataType(qname);
then(dictionaryService).should().getDataType(nodeRef);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).should().getNamespaceURI(any());
then(namespaceService).shouldHaveNoMoreInteractions();
final Serializable convertedCatValueParam = convertedParams.get(categoryAspectKey);
assertTrue(convertedCatValueParam instanceof QName);
assertEquals(CLASSIFIABLE, ((QName) convertedCatValueParam).getLocalName());
assertEquals(CLASSIFIABLE_ASPECT, ((QName) convertedCatValueParam).getPrefixString());
assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedCatValueParam).getNamespaceURI());
final Serializable convertedDestinationParam = convertedParams.get(categoryValueKey);
assertTrue(convertedDestinationParam instanceof NodeRef);
assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedDestinationParam).getStoreRef());
assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedDestinationParam).getId());
}
@Test
public void testRemoveAspectConversion()
{
final String name = RemoveFeaturesActionExecuter.NAME;
final String aspectNameKey = RemoveFeaturesActionExecuter.PARAM_ASPECT_NAME;
final Map<String, Serializable> params = Map.of(aspectNameKey, VERSIONABLE_ASPECT);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(aspectNameKey)).willReturn(actionDefinitionParam1);
final QName qname = DataTypeDefinition.QNAME;
given(actionDefinitionParam1.getType()).willReturn(qname);
given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition1);
given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
then(actionService).should().getActionDefinition(name);
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(aspectNameKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should().getDataType(qname);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).should().getNamespaceURI(any());
then(namespaceService).shouldHaveNoMoreInteractions();
final Serializable convertedParam = convertedParams.get(aspectNameKey);
assertTrue(convertedParam instanceof QName);
assertEquals(VERSIONABLE, ((QName) convertedParam).getLocalName());
assertEquals(VERSIONABLE_ASPECT, ((QName) convertedParam).getPrefixString());
assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedParam).getNamespaceURI());
}
@Test
public void testAddWorkflowConversion()
{
final String name = SimpleWorkflowActionExecuter.NAME;
final String approveStepKey = SimpleWorkflowActionExecuter.PARAM_APPROVE_STEP;
final String approveFolderKey = SimpleWorkflowActionExecuter.PARAM_APPROVE_FOLDER;
final String approveMoveKey = SimpleWorkflowActionExecuter.PARAM_APPROVE_MOVE;
final String rejectStepKey = SimpleWorkflowActionExecuter.PARAM_REJECT_STEP;
final String rejectFolderKey = SimpleWorkflowActionExecuter.PARAM_REJECT_FOLDER;
final String rejectMoveKey = SimpleWorkflowActionExecuter.PARAM_REJECT_MOVE;
final String approve = "Approve";
final String reject = "Reject";
final Map<String, Serializable> params =
Map.of(approveStepKey, approve, approveFolderKey, DUMMY_FOLDER_NODE_ID, approveMoveKey, true,
rejectStepKey, reject, rejectFolderKey, DUMMY_FOLDER_NODE_ID, rejectMoveKey, true);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(rejectStepKey)).willReturn(actionDefinitionParam1);
given(actionDefinition.getParameterDefintion(approveStepKey)).willReturn(actionDefinitionParam1);
final QName text = DataTypeDefinition.TEXT;
given(actionDefinitionParam1.getType()).willReturn(text, text);
given(actionDefinition.getParameterDefintion(rejectFolderKey)).willReturn(actionDefinitionParam2);
given(actionDefinition.getParameterDefintion(approveFolderKey)).willReturn(actionDefinitionParam2);
final QName nodeRef = DataTypeDefinition.NODE_REF;
given(actionDefinitionParam2.getType()).willReturn(nodeRef, nodeRef);
given(actionDefinition.getParameterDefintion(rejectMoveKey)).willReturn(actionDefinitionParam3);
given(actionDefinition.getParameterDefintion(approveMoveKey)).willReturn(actionDefinitionParam3);
final QName bool = DataTypeDefinition.BOOLEAN;
given(actionDefinitionParam3.getType()).willReturn(bool, bool);
given(dictionaryService.getDataType(nodeRef)).willReturn(dataTypeDefinition1);
given(dictionaryService.getDataType(text)).willReturn(dataTypeDefinition2);
given(dataTypeDefinition2.getJavaClassName()).willReturn(String.class.getName());
given(dictionaryService.getDataType(bool)).willReturn(dataTypeDefinition3);
given(dataTypeDefinition3.getJavaClassName()).willReturn(Boolean.class.getName());
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
then(actionService).should().getActionDefinition(name);
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(approveStepKey);
then(actionDefinition).should().getParameterDefintion(approveFolderKey);
then(actionDefinition).should().getParameterDefintion(approveMoveKey);
then(actionDefinition).should().getParameterDefintion(rejectStepKey);
then(actionDefinition).should().getParameterDefintion(rejectFolderKey);
then(actionDefinition).should().getParameterDefintion(rejectMoveKey);
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should(times(4)).getDataType(text);
then(dictionaryService).should(times(2)).getDataType(nodeRef);
then(dictionaryService).should(times(4)).getDataType(bool);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).shouldHaveNoInteractions();
final Serializable convertedApproveStepParam = convertedParams.get(approveStepKey);
assertTrue(convertedApproveStepParam instanceof String);
assertEquals(approve, convertedApproveStepParam);
final Serializable convertedRejectStepParam = convertedParams.get(rejectStepKey);
assertTrue(convertedRejectStepParam instanceof String);
assertEquals(reject, convertedRejectStepParam);
final Serializable convertedApproveFolderParam = convertedParams.get(approveFolderKey);
assertTrue(convertedApproveFolderParam instanceof NodeRef);
assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedApproveFolderParam).getStoreRef());
assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedApproveFolderParam).getId());
final Serializable convertedRejectFolderParam = convertedParams.get(rejectFolderKey);
assertTrue(convertedRejectFolderParam instanceof NodeRef);
assertEquals(STORE_REF_WORKSPACE_SPACESSTORE, ((NodeRef) convertedRejectFolderParam).getStoreRef());
assertEquals(DUMMY_FOLDER_NODE_ID, ((NodeRef) convertedRejectFolderParam).getId());
final Serializable convertedApproveMoveParam = convertedParams.get(approveMoveKey);
assertTrue(convertedApproveMoveParam instanceof Boolean);
assertTrue((Boolean) convertedApproveMoveParam);
final Serializable convertedRejectMoveParam = convertedParams.get(rejectMoveKey);
assertTrue(convertedRejectMoveParam instanceof Boolean);
assertTrue((Boolean) convertedRejectMoveParam);
}
@Test
public void testSetPropertyConversion()
{
final String name = SetPropertyValueActionExecuter.NAME;
final String propertyNameKey = SetPropertyValueActionExecuter.PARAM_PROPERTY;
final String propertyValueKey = SetPropertyValueActionExecuter.PARAM_VALUE;
final String propertyTypeKey = "prop_type";
final String dummy_key_value = "dummy_key_value";
final String propType = "d:text";
final Map<String, Serializable> params =
Map.of(propertyNameKey, IDENTIFIER_ASPECT, propertyValueKey, dummy_key_value, propertyTypeKey, propType);
given(actionService.getActionDefinition(name)).willReturn(actionDefinition);
given(actionDefinition.getParameterDefintion(propertyNameKey)).willReturn(actionDefinitionParam1);
final QName qname = DataTypeDefinition.QNAME;
given(actionDefinitionParam1.getType()).willReturn(qname);
given(actionDefinition.getParameterDefintion(propertyValueKey)).willReturn(actionDefinitionParam2);
final QName any = DataTypeDefinition.ANY;
given(actionDefinitionParam2.getType()).willReturn(any);
given(actionDefinition.getParameterDefintion(propertyTypeKey)).willReturn(null);
given(actionDefinition.getAdhocPropertiesAllowed()).willReturn(true);
given(dictionaryService.getDataType(qname)).willReturn(dataTypeDefinition1);
given(dictionaryService.getDataType(any)).willReturn(dataTypeDefinition2);
given(dataTypeDefinition2.getJavaClassName()).willReturn(Object.class.getName());
given(namespaceService.getNamespaceURI(any())).willReturn(NamespaceService.DICTIONARY_MODEL_1_0_URI);
//when
final Map<String, Serializable> convertedParams = objectUnderTest.getConvertedParams(params, name);
then(actionService).should().getActionDefinition(name);
then(actionService).shouldHaveNoMoreInteractions();
then(actionDefinition).should().getParameterDefintion(propertyNameKey);
then(actionDefinition).should().getParameterDefintion(propertyValueKey);
then(actionDefinition).should().getParameterDefintion(propertyTypeKey);
then(actionDefinition).should().getAdhocPropertiesAllowed();
then(actionDefinition).shouldHaveNoMoreInteractions();
then(dictionaryService).should().getDataType(qname);
then(dictionaryService).should(times(2)).getDataType(any);
then(dictionaryService).shouldHaveNoMoreInteractions();
then(namespaceService).should().getNamespaceURI(any());
then(namespaceService).shouldHaveNoMoreInteractions();
final Serializable convertedPropNameParam = convertedParams.get(propertyNameKey);
assertTrue(convertedPropNameParam instanceof QName);
assertEquals(IDENTIFIER, ((QName) convertedPropNameParam).getLocalName());
assertEquals(IDENTIFIER_ASPECT, ((QName) convertedPropNameParam).getPrefixString());
assertEquals(NamespaceService.DICTIONARY_MODEL_1_0_URI, ((QName) convertedPropNameParam).getNamespaceURI());
final Serializable convertedPropValParam = convertedParams.get(propertyValueKey);
assertTrue(convertedPropValParam instanceof String);
assertEquals(dummy_key_value, convertedPropValParam);
final Serializable convertedPropTypeParam = convertedParams.get(propertyTypeKey);
assertTrue(convertedPropTypeParam instanceof String);
assertEquals(propType, convertedPropTypeParam);
}
@Test
public void testQnameServiceModelParamConversion() {
given(namespaceService.getPrefixes(any())).willReturn(List.of("cm"));
final String qname = "{cm-dummy-prefix}audio";
final Serializable qnameParam = QName.createQName(qname);
//when
final Serializable convertedParam = objectUnderTest.convertParamFromServiceModel(qnameParam);
then(namespaceService).should().getPrefixes(any());
then(namespaceService).shouldHaveNoMoreInteractions();
assertEquals("cm:audio", convertedParam);
}
@Test
public void testNodeRefServiceModelParamConversion() {
//given
final Serializable nodeRefParam = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_FOLDER_NODE_ID);
//when
final Serializable convertedParam = objectUnderTest.convertParamFromServiceModel(nodeRefParam);
then(namespaceService).shouldHaveNoInteractions();
assertEquals(DUMMY_FOLDER_NODE_ID, convertedParam);
}
@Test
public void testOtherServiceModelParamConversion() {
//given
final Serializable dummyStringParam = "dummy-param";
//when
final Serializable convertedParam = objectUnderTest.convertParamFromServiceModel(dummyStringParam);
then(namespaceService).shouldHaveNoInteractions();
assertEquals(dummyStringParam, convertedParam);
}
}

View File

@@ -0,0 +1,117 @@
/*
* #%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.impl.rules;
import static org.alfresco.service.cmr.rule.RuleType.INBOUND;
import static org.alfresco.service.cmr.rule.RuleType.OUTBOUND;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.BDDMockito.then;
import java.util.List;
import junit.framework.TestCase;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.CompositeActionImpl;
import org.alfresco.repo.action.RuntimeActionService;
import org.alfresco.repo.action.executer.CheckOutActionExecuter;
import org.alfresco.repo.action.executer.CopyActionExecuter;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.Rule;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@Experimental
@RunWith(MockitoJUnitRunner.class)
public class ActionPermissionValidatorTest extends TestCase
{
private static final String DUMMY_NODE_ID = "dummy-node-id";
@Mock
private RuntimeActionService runtimeActionService;
@InjectMocks
private ActionPermissionValidator objectUnderTest;
@Test
public void testPositiveRulePermissionValidation()
{
//given
final CompositeActionImpl compositeAction =
new CompositeActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "composite-id");
final Action action1 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-1",
CopyActionExecuter.NAME);
compositeAction.addAction(action1);
final Action action2 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-2",
CheckOutActionExecuter.NAME);
compositeAction.addAction(action2);
final Rule inputRule = new Rule();
inputRule.setAction(compositeAction);
inputRule.setRuleTypes(List.of(INBOUND));
//when
final Rule validatedRule = objectUnderTest.validateRulePermissions(inputRule);
then(runtimeActionService).should().verifyActionAccessRestrictions(action1);
then(runtimeActionService).should().verifyActionAccessRestrictions(action2);
then(runtimeActionService).shouldHaveNoMoreInteractions();
((CompositeActionImpl) validatedRule.getAction()).getActions()
.forEach(action -> Assertions.assertThat(action.getParameterValue("actionContext")).isEqualTo("rule"));
}
@Test
public void testNegativeRulePermissionValidation()
{
//given
final CompositeActionImpl compositeAction =
new CompositeActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "composite-id");
final Action action1 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-1",
CopyActionExecuter.NAME);
compositeAction.addAction(action1);
final Action action2 = new ActionImpl(new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, DUMMY_NODE_ID), "id-2",
CheckOutActionExecuter.NAME);
compositeAction.addAction(action2);
final Rule inputRule = new Rule();
inputRule.setAction(compositeAction);
inputRule.setRuleTypes(List.of(OUTBOUND));
//when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(() -> objectUnderTest.validateRulePermissions(inputRule));
then(runtimeActionService).should().verifyActionAccessRestrictions(action1);
then(runtimeActionService).should().verifyActionAccessRestrictions(action2);
then(runtimeActionService).shouldHaveNoMoreInteractions();
}
}

View File

@@ -0,0 +1,441 @@
/*
* #%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.impl.rules;
import static org.alfresco.model.ContentModel.TYPE_FOLDER;
import static org.alfresco.model.ContentModel.TYPE_SYSTEM_FOLDER;
import static org.alfresco.repo.rule.RuleModel.TYPE_RULE;
import static org.alfresco.rest.api.model.rules.RuleSet.DEFAULT_ID;
import static org.alfresco.service.cmr.security.AccessStatus.ALLOWED;
import static org.alfresco.service.cmr.security.AccessStatus.DENIED;
import static org.alfresco.service.cmr.security.PermissionService.CHANGE_PERMISSIONS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.reset;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.RuleService;
import org.alfresco.service.cmr.security.PermissionService;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class NodeValidatorTest
{
private static final String FOLDER_NODE_ID = "dummy-folder-node-id";
private static final String LINK_TO_NODE_ID = "dummy-link-to-node-id";
private static final String RULE_SET_ID = "dummy-rule-set-id";
private static final String RULE_ID = "dummy-rule-id";
private static final String PARENT_NODE_ID = "dummy-parent-node-id";
private static final NodeRef folderNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID);
private static final NodeRef ruleSetNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
private static final NodeRef ruleNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID);
private static final NodeRef parentNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, PARENT_NODE_ID);
@Mock
private Nodes nodesMock;
@Mock
private Node ruleSetNodeMock;
@Mock
private PermissionService permissionServiceMock;
@Mock
private RuleService ruleServiceMock;
@Mock
private NodeService nodeServiceMock;
@Mock
private ChildAssociationRef primaryParentMock;
@InjectMocks
private NodeValidator nodeValidator;
@Before
public void setUp() throws Exception
{
MockitoAnnotations.openMocks(this);
given(nodesMock.validateOrLookupNode(eq(FOLDER_NODE_ID), any())).willReturn(folderNodeRef);
given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
given(nodesMock.nodeMatches(any(), any(), any())).willReturn(true);
given(permissionServiceMock.hasReadPermission(any())).willReturn(ALLOWED);
given(permissionServiceMock.hasPermission(any(), any())).willReturn(ALLOWED);
}
@Test
public void testValidateFolderNode()
{
// when
final NodeRef nodeRef = nodeValidator.validateFolderNode(FOLDER_NODE_ID, false);
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().nodeMatches(folderNodeRef, Set.of(TYPE_FOLDER), null);
then(nodesMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
assertThat(nodeRef).isNotNull().isEqualTo(folderNodeRef);
}
@Test
public void testValidateFolderNode_notExistingFolder()
{
given(nodesMock.validateOrLookupNode(any(), any())).willThrow(new EntityNotFoundException(FOLDER_NODE_ID));
//when
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
() -> nodeValidator.validateFolderNode(FOLDER_NODE_ID, false));
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testValidateFolderNode_notMatchingTypeFolder()
{
given(nodesMock.nodeMatches(any(), eq(Set.of(TYPE_FOLDER)), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> nodeValidator.validateFolderNode(FOLDER_NODE_ID, false));
then(nodesMock).should().validateOrLookupNode(FOLDER_NODE_ID, null);
then(nodesMock).should().nodeMatches(folderNodeRef, Set.of(TYPE_FOLDER), null);
then(nodesMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testValidateFolderNode_noReadPermission()
{
given(permissionServiceMock.hasReadPermission(any())).willReturn(DENIED);
// when
assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(
() -> nodeValidator.validateFolderNode(FOLDER_NODE_ID, false));
then(permissionServiceMock).should().hasReadPermission(folderNodeRef);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testValidateFolderNode_noChangePermission()
{
given(permissionServiceMock.hasPermission(any(), any())).willReturn(DENIED);
// when
assertThatExceptionOfType(PermissionDeniedException.class).isThrownBy(() ->
nodeValidator.validateFolderNode(folderNodeRef.getId(), true));
then(permissionServiceMock).should().hasPermission(folderNodeRef, CHANGE_PERMISSIONS);
then(permissionServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void validateRuleSetNode()
{
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(true);
// when
final NodeRef nodeRef = nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef);
then(nodesMock).should().validateNode(RULE_SET_ID);
then(nodesMock).should().nodeMatches(ruleSetNodeRef, Set.of(TYPE_SYSTEM_FOLDER), null);
then(nodesMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).shouldHaveNoInteractions();
assertThat(nodeRef).isNotNull().isEqualTo(ruleSetNodeRef);
}
@Test
public void testValidateRuleSetNodeNoParentId()
{
given(nodesMock.getNode(any())).willReturn(ruleSetNodeMock);
given(nodeServiceMock.getPrimaryParent(any())).willReturn(primaryParentMock);
given(primaryParentMock.getParentRef()).willReturn(parentNodeRef);
//when
final NodeRef nodeRef = nodeValidator.validateRuleSetNode(LINK_TO_NODE_ID,true);
assertThat(nodeRef).isNotNull().isEqualTo(parentNodeRef);
}
@Test
public void validateRuleSetNode_defaultId()
{
given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef);
// when
final NodeRef nodeRef = nodeValidator.validateRuleSetNode(DEFAULT_ID, folderNodeRef);
then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(nodesMock).shouldHaveNoInteractions();
then(permissionServiceMock).shouldHaveNoInteractions();
assertThat(nodeRef).isNotNull().isEqualTo(ruleSetNodeRef);
}
@Test
public void testValidateRuleSetNode_notExistingRuleSet()
{
given(nodesMock.validateNode(RULE_SET_ID)).willThrow(new EntityNotFoundException(RULE_SET_ID));
//when
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
() -> nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef));
then(nodesMock).should().validateNode(RULE_SET_ID);
then(nodesMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testValidateRuleSetNode_notMatchingTypeSystemFolder()
{
given(nodesMock.nodeMatches(any(), eq(Set.of(TYPE_SYSTEM_FOLDER)), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef));
then(nodesMock).should().validateNode(RULE_SET_ID);
then(nodesMock).should().nodeMatches(ruleSetNodeRef, Set.of(TYPE_SYSTEM_FOLDER), null);
then(nodesMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testValidateRuleSetNode_notExistingDefaultRuleSet()
{
given(ruleServiceMock.getRuleSetNode(folderNodeRef)).willReturn(null);
// when
assertThatExceptionOfType(RelationshipResourceNotFoundException.class).isThrownBy(
() -> nodeValidator.validateRuleSetNode(DEFAULT_ID, folderNodeRef));
then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(nodesMock).shouldHaveNoInteractions();
}
@Test
public void testValidateRuleSetNode_notAssociatedRuleSetToFolder()
{
given(ruleServiceMock.isRuleSetAssociatedWithFolder(any(), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> nodeValidator.validateRuleSetNode(RULE_SET_ID, folderNodeRef));
then(ruleServiceMock).should().isRuleSetAssociatedWithFolder(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void validateRuleNode()
{
given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(true);
// when
final NodeRef nodeRef = nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef);
then(nodesMock).should().validateNode(RULE_ID);
then(nodesMock).should().nodeMatches(ruleNodeRef, Set.of(TYPE_RULE), null);
then(nodesMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(permissionServiceMock).shouldHaveNoInteractions();
assertThat(nodeRef).isNotNull().isEqualTo(ruleNodeRef);
}
@Test
public void validateRuleNode_nullRuleSet()
{
// when
final NodeRef nodeRef = nodeValidator.validateRuleNode(RULE_ID, null);
then(nodesMock).should().validateNode(RULE_ID);
then(nodesMock).should().nodeMatches(ruleNodeRef, Set.of(TYPE_RULE), null);
then(nodesMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
then(permissionServiceMock).shouldHaveNoInteractions();
assertThat(nodeRef).isNotNull().isEqualTo(ruleNodeRef);
}
@Test
public void testValidateRuleNode_notExistingRule()
{
given(nodesMock.validateNode(RULE_ID)).willThrow(new EntityNotFoundException(RULE_ID));
//when
assertThatExceptionOfType(EntityNotFoundException.class).isThrownBy(
() -> nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef));
then(nodesMock).should().validateNode(RULE_ID);
then(nodesMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testValidateRuleNode_notMatchingTypeRule()
{
given(nodesMock.nodeMatches(any(), eq(Set.of(TYPE_RULE)), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef));
then(nodesMock).should().validateNode(RULE_ID);
then(nodesMock).should().nodeMatches(ruleNodeRef, Set.of(TYPE_RULE), null);
then(nodesMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testValidateRuleNode_notAssociatedRuleToRuleSet()
{
given(ruleServiceMock.isRuleAssociatedWithRuleSet(any(), any())).willReturn(false);
// when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> nodeValidator.validateRuleNode(RULE_ID, ruleSetNodeRef));
then(ruleServiceMock).should().isRuleAssociatedWithRuleSet(ruleNodeRef, ruleSetNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testIsRuleSetNode()
{
//resetting mock to bypass setup method
resetNodesMock();
boolean actual = nodeValidator.isRuleSetNode(RULE_SET_ID);
Assert.assertTrue(actual);
}
@Test
public void testIsNotRuleSetNode()
{
//resetting mock to bypass setup method
resetNodesMock();
//using an id that doesn't belong to a ruleset node
boolean actual = nodeValidator.isRuleSetNode(FOLDER_NODE_ID);
Assert.assertFalse(actual);
}
@Test
public void testIsRuleSetNotNullAndShared()
{
given(ruleServiceMock.isRuleSetShared(any())).willReturn(true);
// when
final boolean shared = nodeValidator.isRuleSetNotNullAndShared(ruleSetNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(shared).isTrue();
}
@Test
public void testIsRuleSetNotNullAndShared_nullRuleSetNode()
{
// when
final boolean shared = nodeValidator.isRuleSetNotNullAndShared(null);
then(ruleServiceMock).shouldHaveNoInteractions();
assertThat(shared).isFalse();
}
@Test
public void testIsRuleSetNotNullAndShared_withoutRuleSetAndWithFolder()
{
given(ruleServiceMock.getRuleSetNode(any())).willReturn(ruleSetNodeRef);
// when
nodeValidator.isRuleSetNotNullAndShared(null, folderNodeRef);
then(ruleServiceMock).should().getRuleSetNode(folderNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testIsRuleSetNotNullAndShared_withRuleSetAndWithFolder()
{
// when
nodeValidator.isRuleSetNotNullAndShared(ruleSetNodeRef, folderNodeRef);
then(ruleServiceMock).should().isRuleSetShared(ruleSetNodeRef);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
private void resetNodesMock() {
reset(nodesMock);
given(nodesMock.validateOrLookupNode(eq(FOLDER_NODE_ID), any())).willReturn(folderNodeRef);
given(nodesMock.validateNode(RULE_SET_ID)).willReturn(ruleSetNodeRef);
given(nodesMock.validateNode(RULE_ID)).willReturn(ruleNodeRef);
given(nodesMock.nodeMatches(ruleSetNodeRef, Set.of(ContentModel.TYPE_SYSTEM_FOLDER), null)).willReturn(true);
}
}

View File

@@ -0,0 +1,121 @@
/*
* #%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.impl.rules;
import static java.util.Collections.emptyList;
import static org.alfresco.rest.api.impl.rules.RuleLoader.IS_SHARED;
import static org.alfresco.rest.api.model.rules.RuleTrigger.OUTBOUND;
import static org.alfresco.rest.api.model.rules.RuleTrigger.UPDATE;
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.MockitoAnnotations.openMocks;
import java.util.List;
import org.alfresco.rest.api.model.rules.Rule;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.rule.RuleService;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
/** Unit tests for {@link RuleLoader}. */
public class RuleLoaderTest
{
private static final String NODE_ID = "node-id";
private static final NodeRef NODE_REF = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, NODE_ID);
private static final String TITLE = "title";
private static final String DESCRIPTION = "description";
private static final boolean ENABLED = true;
private static final boolean CASCADE = true;
private static final boolean EXECUTE_ASYNCHRONOUSLY = false;
private static final List<String> TRIGGERS = List.of("update", "outbound");
private static final NodeRef RULE_SET_NODE = new NodeRef("rule://set/");
@InjectMocks
private RuleLoader ruleLoader;
@Mock
private RuleService ruleServiceMock;
@Mock
private NodeValidator nodeValidatorMock;
private org.alfresco.service.cmr.rule.Rule serviceRule = createServiceRule();
@Before
public void setUp()
{
openMocks(this);
}
@Test
public void testLoadRule()
{
Rule rule = ruleLoader.loadRule(serviceRule, emptyList());
Rule expected = Rule.builder().id(NODE_ID)
.name(TITLE)
.description(DESCRIPTION)
.enabled(ENABLED)
.cascade(CASCADE)
.asynchronous(EXECUTE_ASYNCHRONOUSLY)
.triggers(List.of(UPDATE, OUTBOUND)).create();
assertThat(rule).isEqualTo(expected);
}
@Test
public void testLoadRule_noExceptionWithNullInclude()
{
ruleLoader.loadRule(serviceRule, null);
}
@Test
public void testLoadRule_includeIsShared()
{
// Simulate the rule set being shared.
given(ruleServiceMock.getRuleSetNode(NODE_REF)).willReturn(RULE_SET_NODE);
given(nodeValidatorMock.isRuleSetNotNullAndShared(RULE_SET_NODE)).willReturn(true);
Rule rule = ruleLoader.loadRule(serviceRule, List.of(IS_SHARED));
assertThat(rule).extracting("isShared").isEqualTo(true);
}
private org.alfresco.service.cmr.rule.Rule createServiceRule()
{
org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
rule.setNodeRef(NODE_REF);
rule.setTitle(TITLE);
rule.setDescription(DESCRIPTION);
rule.setRuleDisabled(!ENABLED);
rule.applyToChildren(CASCADE);
rule.setExecuteAsynchronously(EXECUTE_ASYNCHRONOUSLY);
rule.setRuleTypes(TRIGGERS);
return rule;
}
}

View File

@@ -0,0 +1,133 @@
/*
* #%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.impl.rules;
import static org.alfresco.rest.api.impl.rules.RuleSetLoader.INCLUSION_TYPE;
import static org.alfresco.rest.api.impl.rules.RuleSetLoader.OWNING_FOLDER;
import static org.alfresco.rest.api.model.rules.InclusionType.INHERITED;
import static org.alfresco.rest.api.model.rules.InclusionType.LINKED;
import static org.alfresco.rest.api.model.rules.InclusionType.OWNED;
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
import static org.mockito.BDDMockito.given;
import java.util.List;
import junit.framework.TestCase;
import org.alfresco.rest.api.model.rules.RuleSet;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
/** Unit tests for {@link RuleSetLoader}. */
@Experimental
@RunWith (MockitoJUnitRunner.class)
public class RuleSetLoaderTest extends TestCase
{
private static final String FOLDER_ID = "dummy-folder-id";
private static final String RULE_SET_ID = "dummy-rule-set-id";
private static final NodeRef FOLDER_NODE = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_ID);
private static final NodeRef RULE_SET_NODE = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
private static final String LINKING_FOLDER_ID = "linking-folder";
private static final NodeRef LINKING_FOLDER = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, LINKING_FOLDER_ID);
private static final NodeRef INHERITING_FOLDER = new NodeRef("inheriting://folder/");
@InjectMocks
private RuleSetLoader ruleSetLoader;
@Mock
private NodeService nodeServiceMock;
@Mock
private ChildAssociationRef ruleSetAssociationMock;
@Mock
private ChildAssociationRef linkAssociationMock;
@Before
@Override
public void setUp()
{
given(ruleSetAssociationMock.getParentRef()).willReturn(FOLDER_NODE);
given(nodeServiceMock.getPrimaryParent(RULE_SET_NODE)).willReturn(ruleSetAssociationMock);
given(linkAssociationMock.getParentRef()).willReturn(LINKING_FOLDER);
given(nodeServiceMock.getParentAssocs(RULE_SET_NODE)).willReturn(List.of(ruleSetAssociationMock, linkAssociationMock));
}
@Test
public void testLoadRuleSet_noIncludes()
{
// Call the method under test.
RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, FOLDER_NODE, null);
RuleSet expected = RuleSet.builder().id(RULE_SET_ID).create();
assertEquals(expected, actual);
}
@Test
public void testLoadRuleSet_includeOwningFolder()
{
// Call the method under test.
RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, FOLDER_NODE, List.of(OWNING_FOLDER));
RuleSet expected = RuleSet.builder().id(RULE_SET_ID).owningFolder(FOLDER_NODE).create();
assertEquals(expected, actual);
}
@Test
public void testLoadRuleSet_includeInclusionType()
{
// Call the method under test.
RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, FOLDER_NODE, List.of(INCLUSION_TYPE));
RuleSet expected = RuleSet.builder().id(RULE_SET_ID).inclusionType(OWNED).create();
assertEquals(expected, actual);
}
@Test
public void testLoadRuleSet_linkedInclusionType()
{
// Call the method under test.
RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, LINKING_FOLDER, List.of(INCLUSION_TYPE));
RuleSet expected = RuleSet.builder().id(RULE_SET_ID).inclusionType(LINKED).create();
assertEquals(expected, actual);
}
@Test
public void testLoadRuleSet_inheritedInclusionType()
{
// Call the method under test.
RuleSet actual = ruleSetLoader.loadRuleSet(RULE_SET_NODE, INHERITING_FOLDER, List.of(INCLUSION_TYPE));
RuleSet expected = RuleSet.builder().id(RULE_SET_ID).inclusionType(INHERITED).create();
assertEquals(expected, actual);
}
}

View File

@@ -0,0 +1,236 @@
/*
* #%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.impl.rules;
import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import java.util.Collection;
import java.util.List;
import junit.framework.TestCase;
import org.alfresco.repo.rule.RuleModel;
import org.alfresco.repo.rule.RuntimeRuleService;
import org.alfresco.rest.api.model.rules.RuleSet;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.RuleService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
/** Unit tests for {@link RuleSetsImpl}. */
@Experimental
@RunWith (MockitoJUnitRunner.class)
public class RuleSetsImplTest extends TestCase
{
private static final String FOLDER_ID = "dummy-folder-id";
private static final String LINK_TO_NODE_ID = "dummy-link-to-node-id";
private static final String RULE_SET_ID = "dummy-rule-set-id";
private static final NodeRef FOLDER_NODE = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_ID);
private static final NodeRef LINK_TO_NODE = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, LINK_TO_NODE_ID);
private static final NodeRef RULE_SET_NODE = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
private static final Paging PAGING = Paging.DEFAULT;
private static final List<String> INCLUDES = List.of("dummy-includes");
@InjectMocks
private RuleSetsImpl ruleSets;
@Mock
private RuleSetLoader ruleSetLoaderMock;
@Mock
private NodeValidator nodeValidatorMock;
@Mock
private NodeService nodeServiceMock;
@Mock
private RuleService ruleServiceMock;
@Mock
private RuntimeRuleService runtimeRuleServiceMock;
@Mock
private RuleSet ruleSetMock;
@Mock
private ChildAssociationRef assocRef;
@Before
@Override
public void setUp()
{
MockitoAnnotations.openMocks(this);
given(nodeValidatorMock.validateFolderNode(eq(LINK_TO_NODE_ID), anyBoolean())).willReturn(LINK_TO_NODE);
given(nodeValidatorMock.validateRuleSetNode(LINK_TO_NODE_ID,true)).willReturn(LINK_TO_NODE);
given(nodeValidatorMock.validateFolderNode(eq(FOLDER_ID), anyBoolean())).willReturn(FOLDER_NODE);
given(nodeValidatorMock.validateRuleSetNode(RULE_SET_ID, FOLDER_NODE)).willReturn(RULE_SET_NODE);
given(ruleServiceMock.getRuleSetNode(FOLDER_NODE)).willReturn(RULE_SET_NODE);
given(ruleSetLoaderMock.loadRuleSet(RULE_SET_NODE, FOLDER_NODE, INCLUDES)).willReturn(ruleSetMock);
}
@Test
public void testGetRuleSets()
{
// Call the method under test.
CollectionWithPagingInfo<RuleSet> actual = ruleSets.getRuleSets(FOLDER_ID, INCLUDES, PAGING);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().getRuleSetNode(FOLDER_NODE);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
Collection<RuleSet> expected = List.of(ruleSetMock);
assertEquals(expected, actual.getCollection());
assertEquals(PAGING, actual.getPaging());
}
@Test
public void testGetZeroRuleSets()
{
// Simulate no rule sets for the folder.
given(ruleServiceMock.getRuleSetNode(FOLDER_NODE)).willReturn(null);
// Call the method under test.
CollectionWithPagingInfo<RuleSet> actual = ruleSets.getRuleSets(FOLDER_ID, INCLUDES, PAGING);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().getRuleSetNode(FOLDER_NODE);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertEquals(emptyList(), actual.getCollection());
assertEquals(PAGING, actual.getPaging());
}
@Test
public void testGetRuleSetById()
{
// Call the method under test.
RuleSet actual = ruleSets.getRuleSetById(FOLDER_ID, RULE_SET_ID, INCLUDES);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID, false);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
assertEquals(ruleSetMock, actual);
}
@Test
public void testLinkToFolderRuleSet()
{
NodeRef childNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "dummy-child-id");
given(ruleServiceMock.hasRules(any(NodeRef.class))).willReturn(true, false);
given(runtimeRuleServiceMock.getSavedRuleFolderAssoc(any(NodeRef.class))).willReturn(assocRef);
given(assocRef.getChildRef()).willReturn(childNodeRef);
//when
String actual = ruleSets.linkToRuleSet(FOLDER_ID,LINK_TO_NODE_ID).getId();
then(ruleServiceMock).should().hasRules(LINK_TO_NODE);
then(ruleServiceMock).should().hasRules(FOLDER_NODE);
then(runtimeRuleServiceMock).should().getSavedRuleFolderAssoc(LINK_TO_NODE);
then(runtimeRuleServiceMock).shouldHaveNoMoreInteractions();
then(nodeServiceMock).should().addChild(FOLDER_NODE, childNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER);
then(nodeServiceMock).shouldHaveNoMoreInteractions();
assertEquals(childNodeRef.getId(),actual);
}
@Test
public void testLinkToRuleSet()
{
NodeRef childNodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "dummy-child-id");
given(nodeValidatorMock.isRuleSetNode(any())).willReturn(true);
given(ruleServiceMock.hasRules(any(NodeRef.class))).willReturn(true, false);
given(runtimeRuleServiceMock.getSavedRuleFolderAssoc(any(NodeRef.class))).willReturn(assocRef);
given(assocRef.getChildRef()).willReturn(childNodeRef);
//when
String actual = ruleSets.linkToRuleSet(FOLDER_ID,LINK_TO_NODE_ID).getId();
then(nodeValidatorMock).should().validateFolderNode(FOLDER_ID,true);
then(nodeValidatorMock).should().isRuleSetNode(LINK_TO_NODE_ID);
then(nodeValidatorMock).should().validateRuleSetNode(LINK_TO_NODE_ID,true);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().hasRules(LINK_TO_NODE);
then(ruleServiceMock).should().hasRules(FOLDER_NODE);
then(runtimeRuleServiceMock).should().getSavedRuleFolderAssoc(LINK_TO_NODE);
then(runtimeRuleServiceMock).shouldHaveNoMoreInteractions();
then(nodeServiceMock).should().addChild(FOLDER_NODE, childNodeRef, RuleModel.ASSOC_RULE_FOLDER, RuleModel.ASSOC_RULE_FOLDER);
then(nodeServiceMock).shouldHaveNoMoreInteractions();
assertEquals(childNodeRef.getId(),actual);
}
@Test
public void testLinkToRuleSet_targetFolderHasNoRules()
{
given(ruleServiceMock.hasRules(LINK_TO_NODE)).willReturn(false);
//when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> ruleSets.linkToRuleSet(FOLDER_ID, LINK_TO_NODE_ID)
);
then(nodeServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().hasRules(LINK_TO_NODE);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(runtimeRuleServiceMock).shouldHaveNoInteractions();
}
@Test
public void testLinkToRuleSet_folderShouldntHavePreExistingRules()
{
given(ruleServiceMock.hasRules(any(NodeRef.class))).willReturn(true, true);
//when
assertThatExceptionOfType(InvalidArgumentException.class).isThrownBy(
() -> ruleSets.linkToRuleSet(FOLDER_ID, LINK_TO_NODE_ID));
then(nodeServiceMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().hasRules(LINK_TO_NODE);
then(ruleServiceMock).should().hasRules(FOLDER_NODE);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(runtimeRuleServiceMock).shouldHaveNoInteractions();
}
}

View File

@@ -0,0 +1,145 @@
/*
* #%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.impl.rules;
import static java.util.Collections.emptyMap;
import static org.alfresco.repo.rule.RuleModel.ASPECT_IGNORE_INHERITED_RULES;
import static org.alfresco.rest.api.model.rules.RuleSetting.IS_INHERITANCE_ENABLED_KEY;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import junit.framework.TestCase;
import org.alfresco.rest.api.model.rules.RuleSetting;
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
/** Unit tests for {@link RuleSettingsImpl}. */
@Experimental
@RunWith (MockitoJUnitRunner.class)
public class RuleSettingsImplTest extends TestCase
{
private static final String FOLDER_ID = "dummy-folder-id";
private static final NodeRef FOLDER_NODE = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_ID);
@InjectMocks
private RuleSettingsImpl ruleSettings;
@Mock
private NodeValidator nodeValidatorMock;
@Mock
private NodeService nodeServiceMock;
@Before
@Override
public void setUp()
{
given(nodeValidatorMock.validateFolderNode(eq(FOLDER_ID), anyBoolean())).willReturn(FOLDER_NODE);
}
@Test
public void testGetRuleSetting_disabled()
{
given(nodeServiceMock.hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES)).willReturn(true);
// Call the method under test.
RuleSetting ruleSetting = ruleSettings.getRuleSetting(FOLDER_ID, IS_INHERITANCE_ENABLED_KEY);
RuleSetting expected = RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(false).create();
assertEquals(expected, ruleSetting);
}
@Test
public void testGetRuleSetting_enabled()
{
given(nodeServiceMock.hasAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES)).willReturn(false);
// Call the method under test.
RuleSetting ruleSetting = ruleSettings.getRuleSetting(FOLDER_ID, IS_INHERITANCE_ENABLED_KEY);
RuleSetting expected = RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(true).create();
assertEquals(expected, ruleSetting);
}
@Test
public void testGetRuleSetting_unrecognisedKey()
{
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> ruleSettings.getRuleSetting(FOLDER_ID, "-fakeSetting-"));
}
@Test
public void testSetRuleSetting_enable()
{
RuleSetting ruleSetting = RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(true).create();
// Call the method under test.
RuleSetting actual = ruleSettings.setRuleSetting(FOLDER_ID, ruleSetting);
assertEquals(ruleSetting, actual);
then(nodeServiceMock).should().removeAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES);
}
@Test
public void testSetRuleSetting_disable()
{
RuleSetting ruleSetting = RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(false).create();
// Call the method under test.
RuleSetting actual = ruleSettings.setRuleSetting(FOLDER_ID, ruleSetting);
assertEquals(ruleSetting, actual);
then(nodeServiceMock).should().addAspect(FOLDER_NODE, ASPECT_IGNORE_INHERITED_RULES, emptyMap());
}
@Test
public void testSetRuleSetting_unrecognisedKey()
{
RuleSetting ruleSetting = RuleSetting.builder().key("-fakeSetting-").value(true).create();
assertThatExceptionOfType(NotFoundException.class)
.isThrownBy(() -> ruleSettings.setRuleSetting(FOLDER_ID, ruleSetting));
}
@Test
public void testSetRuleSetting_nonBooleanValue()
{
RuleSetting ruleSetting = RuleSetting.builder().key(IS_INHERITANCE_ENABLED_KEY).value(123456).create();
assertThatExceptionOfType(IllegalArgumentException.class)
.isThrownBy(() -> ruleSettings.setRuleSetting(FOLDER_ID, ruleSetting));
}
}

View File

@@ -0,0 +1,628 @@
/*
* #%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.impl.rules;
import static java.util.Collections.emptyList;
import static org.alfresco.rest.api.model.rules.RuleSet.DEFAULT_ID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
import junit.framework.TestCase;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.CompositeActionImpl;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.rules.Rule;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.core.exceptions.RelationshipResourceNotFoundException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.CompositeAction;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.RuleService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
@Experimental
@RunWith(MockitoJUnitRunner.class)
public class RulesImplTest extends TestCase
{
private static final String FOLDER_NODE_ID = "dummy-folder-node-id";
private static final String RULE_SET_ID = "dummy-rule-set-id";
private static final String RULE_ID = "dummy-rule-id";
private static final NodeRef FOLDER_NODE_REF = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, FOLDER_NODE_ID);
private static final NodeRef RULE_SET_NODE_REF = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_SET_ID);
private static final NodeRef RULE_NODE_REF = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID);
private static final Paging PAGING = Paging.DEFAULT;
private static final List<String> INCLUDE = emptyList();
private static final String ACTION_DEFINITION_NAME = "actionDefinitionName";
private static final Map<String, Serializable> DUMMY_PARAMS = Map.of("dummy-key", "dummy-value");
@Mock
private Nodes nodesMock;
@Mock
private NodeValidator nodeValidatorMock;
@Mock
private RuleService ruleServiceMock;
@Mock
private RuleLoader ruleLoaderMock;
@Mock
private ActionParameterConverter actionParameterConverterMock;
@Mock
private ActionPermissionValidator actionPermissionValidatorMock;
@Mock
private org.alfresco.service.cmr.rule.Rule serviceRuleMock;
@Mock
private Rule ruleMock;
private org.alfresco.service.cmr.rule.Rule ruleModel = createRule(RULE_ID);
private CompositeAction compositeAction = new CompositeActionImpl(RULE_NODE_REF, "compositeActionId");
@InjectMocks
private RulesImpl rules;
@Before
@Override
public void setUp() throws Exception
{
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(RULE_SET_NODE_REF);
given(nodeValidatorMock.validateRuleNode(any(), any())).willReturn(RULE_NODE_REF);
given(ruleServiceMock.getRule(RULE_NODE_REF)).willReturn(ruleModel);
given(ruleServiceMock.getRules(FOLDER_NODE_REF)).willReturn(List.of(ruleModel));
given(ruleLoaderMock.loadRule(ruleModel, INCLUDE)).willReturn(ruleMock);
compositeAction.addAction(new ActionImpl(FOLDER_NODE_REF, "actionId", ACTION_DEFINITION_NAME, DUMMY_PARAMS));
}
@Test
public void testGetRules()
{
given(ruleLoaderMock.loadRule(ruleModel, emptyList())).willReturn(ruleMock);
// when
final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(ruleLoaderMock).should().loadRule(ruleModel, emptyList());
then(ruleLoaderMock).shouldHaveNoMoreInteractions();
assertThat(rulesPage)
.isNotNull()
.extracting(CollectionWithPagingInfo::getCollection)
.isNotNull()
.extracting(Collection::size)
.isEqualTo(1);
assertThat(rulesPage.getCollection().stream().findFirst().get()).isEqualTo(ruleMock);
}
@Test
public void testGetRules_emptyResult()
{
given(ruleServiceMock.getRules(any())).willReturn(emptyList());
// when
final CollectionWithPagingInfo<Rule> rulesPage = rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING);
then(ruleServiceMock).should().getRules(FOLDER_NODE_REF);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rulesPage)
.isNotNull()
.extracting(CollectionWithPagingInfo::getCollection)
.isNotNull()
.extracting(Collection::isEmpty)
.isEqualTo(true);
}
@Test
public void testGetRules_invalidFolder()
{
for (Exception exception : folderValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
@Test
public void testGetRules_invalidRuleSet()
{
for (Exception exception : ruleSetValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.getRules(FOLDER_NODE_ID, RULE_SET_ID, INCLUDE, PAGING));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
@Test
public void testGetRuleById()
{
// when
final Rule rule = rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID, INCLUDE);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(nodesMock).shouldHaveNoInteractions();
then(ruleServiceMock).should().getRule(RULE_NODE_REF);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(rule).isEqualTo(ruleMock);
}
@Test
public void testGetRuleById_invalidFolder()
{
for (Exception exception : folderValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID, INCLUDE));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
@Test
public void testGetRuleById_invalidRuleSet()
{
for (Exception exception : ruleSetValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID, INCLUDE));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
@Test
public void testGetRuleById_invalidRule()
{
for (Exception exception : ruleValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(RULE_SET_NODE_REF);
given(nodeValidatorMock.validateRuleNode(any(), any())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.getRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID, INCLUDE));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, false);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
/**
* Create a single rule.
*/
@Test
public void testCreateRules()
{
List<Rule> ruleList = List.of(ruleMock);
given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock);
given(serviceRuleMock.getAction()).willReturn(compositeAction);
given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(arg -> arg.getArguments()[1]);
given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock);
given(actionPermissionValidatorMock.validateRulePermissions(any())).willAnswer(arg -> arg.getArguments()[0]);
// when
List<Rule> actual = rules.createRules(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), ruleList, INCLUDE);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(actionParameterConverterMock).should().getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME);
then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock);
then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock));
then(ruleServiceMock).shouldHaveNoMoreInteractions();
List<Rule> expected = List.of(ruleMock);
assertThat(actual).isEqualTo(expected);
}
/**
* Check that when passing the default rule set then we don't perform any validation around the rule set node.
*/
@Test
public void testCreateRules_defaultRuleSet()
{
List<Rule> ruleList = List.of(ruleMock);
given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock);
given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(arg -> arg.getArguments()[1]);
given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock);
given(serviceRuleMock.getAction()).willReturn(compositeAction);
given(actionPermissionValidatorMock.validateRulePermissions(any())).willAnswer(arg -> arg.getArguments()[0]);
// when
List<Rule> actual = rules.createRules(FOLDER_NODE_REF.getId(), DEFAULT_ID, ruleList, INCLUDE);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(actionParameterConverterMock).should().getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME);
then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock);
then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleMock.toServiceModel(nodesMock));
then(ruleServiceMock).shouldHaveNoMoreInteractions();
List<Rule> expected = List.of(ruleMock);
assertThat(actual).isEqualTo(expected);
}
@Test
public void testCreateRules_emptyRuleList()
{
List<Rule> ruleList = emptyList();
// when
List<Rule> actual = rules.createRules(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), ruleList, INCLUDE);
then(ruleServiceMock).shouldHaveNoInteractions();
assertThat(actual).isEqualTo(emptyList());
}
/**
* Create three rules in a single call and check they are all passed to the RuleService.
*/
@Test
public void testCreateRules_createMultipleRules()
{
List<Rule> ruleBodyList = new ArrayList<>();
List<Rule> expected = new ArrayList<>();
IntStream.range(0, 3).forEach(i -> {
Rule ruleBodyMock = mock(Rule.class);
ruleBodyList.add(ruleBodyMock);
org.alfresco.service.cmr.rule.Rule serviceRuleMockInner = mock(org.alfresco.service.cmr.rule.Rule.class);
given(ruleBodyMock.toServiceModel(nodesMock)).willReturn(serviceRuleMockInner);
final CompositeAction compositeActionInner = new CompositeActionImpl(RULE_NODE_REF, "compositeActionInnerId");
compositeActionInner.addAction(new ActionImpl(FOLDER_NODE_REF, "actionInnerId", ACTION_DEFINITION_NAME, DUMMY_PARAMS));
given(serviceRuleMockInner.getAction()).willReturn(compositeActionInner);
given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMockInner)).willAnswer(arg -> arg.getArguments()[1]);
Rule ruleMockInner = mock(Rule.class);
given(ruleLoaderMock.loadRule(serviceRuleMockInner, INCLUDE)).willReturn(ruleMockInner);
expected.add(ruleMockInner);
given(actionPermissionValidatorMock.validateRulePermissions(any())).willAnswer(arg -> arg.getArguments()[0]);
});
// when
List<Rule> actual = rules.createRules(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), ruleBodyList, INCLUDE);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
for (Rule ruleBody : ruleBodyList)
{
then(actionPermissionValidatorMock).should().validateRulePermissions(ruleBody.toServiceModel(nodesMock));
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, ruleBody.toServiceModel(nodesMock));
}
then(actionParameterConverterMock).should(times(3)).getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME);
then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoMoreInteractions();
assertThat(actual).isEqualTo(expected);
}
@Test
public void testCreateRules_invalidFolder()
{
for (Exception exception : folderValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.createRules(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), emptyList(), INCLUDE));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
@Test
public void testCreateRules_invalidRuleSet()
{
for (Exception exception : ruleSetValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.createRules(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), emptyList(), INCLUDE));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
/**
* Check that we can update a rule.
*/
@Test
public void testUpdateRuleById()
{
given(ruleMock.toServiceModel(nodesMock)).willReturn(serviceRuleMock);
given(ruleServiceMock.saveRule(FOLDER_NODE_REF, serviceRuleMock)).willAnswer(a -> a.getArguments()[1]);
given(serviceRuleMock.getAction()).willReturn(compositeAction);
given(ruleLoaderMock.loadRule(serviceRuleMock, INCLUDE)).willReturn(ruleMock);
given(actionPermissionValidatorMock.validateRulePermissions(any())).willAnswer(arg -> arg.getArguments()[0]);
// when
Rule updatedRule = rules.updateRuleById(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), RULE_ID, ruleMock, INCLUDE);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).should().saveRule(FOLDER_NODE_REF, serviceRuleMock);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
then(actionParameterConverterMock).should().getConvertedParams(DUMMY_PARAMS, ACTION_DEFINITION_NAME);
then(actionParameterConverterMock).shouldHaveNoMoreInteractions();
then(actionPermissionValidatorMock).should().validateRulePermissions(serviceRuleMock);
then(actionPermissionValidatorMock).shouldHaveNoMoreInteractions();
assertThat(updatedRule).isEqualTo(ruleMock);
}
@Test
public void testUpdateRuleById_invalidFolder()
{
for (Exception exception : folderValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.updateRuleById(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), RULE_ID, mock(Rule.class), INCLUDE));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
@Test
public void testUpdateRuleById_invalidRuleSet()
{
for (Exception exception : ruleSetValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.updateRuleById(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), RULE_ID, mock(Rule.class), INCLUDE));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
@Test
public void testUpdateRuleById_invalidRule()
{
for (Exception exception : ruleValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(RULE_SET_NODE_REF);
given(nodeValidatorMock.validateRuleNode(any(), any())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.updateRuleById(FOLDER_NODE_REF.getId(), RULE_SET_NODE_REF.getId(), RULE_ID, mock(Rule.class), INCLUDE));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
@Test
public void testDeleteRuleById()
{
//when
rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID);
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(nodesMock).shouldHaveNoInteractions();
then(ruleServiceMock).should().getRule(RULE_NODE_REF);
then(ruleServiceMock).should().removeRule(FOLDER_NODE_REF, ruleModel);
then(ruleServiceMock).shouldHaveNoMoreInteractions();
}
@Test
public void testDeleteRuleById_invalidFolder()
{
for (Exception exception : folderValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
@Test
public void testDeleteRuleById_invalidRuleSet()
{
for (Exception exception : ruleSetValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
given(nodeValidatorMock.validateRuleSetNode(any(), any())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
@Test
public void testDeleteRuleById_invalidRule()
{
for (Exception exception : ruleValidationExceptions())
{
Mockito.reset(nodeValidatorMock);
given(nodeValidatorMock.validateFolderNode(any(), anyBoolean())).willReturn(FOLDER_NODE_REF);
given(nodeValidatorMock.validateRuleSetNode(any(), any())).willReturn(RULE_SET_NODE_REF);
given(nodeValidatorMock.validateRuleNode(any(), any())).willThrow(exception);
// when
assertThatExceptionOfType(exception.getClass()).isThrownBy(
() -> rules.deleteRuleById(FOLDER_NODE_ID, RULE_SET_ID, RULE_ID));
then(nodeValidatorMock).should().validateFolderNode(FOLDER_NODE_ID, true);
then(nodeValidatorMock).should().validateRuleSetNode(RULE_SET_ID, FOLDER_NODE_REF);
then(nodeValidatorMock).should().validateRuleNode(RULE_ID, RULE_SET_NODE_REF);
then(nodeValidatorMock).shouldHaveNoMoreInteractions();
then(ruleServiceMock).shouldHaveNoInteractions();
}
}
private static org.alfresco.service.cmr.rule.Rule createRule(final String id)
{
final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id);
final org.alfresco.service.cmr.rule.Rule rule = new org.alfresco.service.cmr.rule.Rule();
rule.setNodeRef(nodeRef);
rule.setRuleType("ruleType");
return rule;
}
private static List<Exception> folderValidationExceptions()
{
return List.of(
new EntityNotFoundException(FOLDER_NODE_ID),
new InvalidArgumentException(),
new PermissionDeniedException()
);
}
private static List<Exception> ruleSetValidationExceptions()
{
return List.of(
new EntityNotFoundException(RULE_SET_ID),
new InvalidArgumentException(),
new RelationshipResourceNotFoundException(RULE_SET_ID, "fake-relationship-id")
);
}
private static List<Exception> ruleValidationExceptions()
{
return List.of(
new EntityNotFoundException(RULE_ID),
new InvalidArgumentException(),
new RelationshipResourceNotFoundException(RULE_ID, "fake-relationship-id")
);
}
}

View File

@@ -0,0 +1,79 @@
/*
* #%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.model.rules;
import static org.alfresco.repo.action.executer.SetPropertyValueActionExecuter.PARAM_PROPERTY;
import static org.alfresco.repo.action.executer.SetPropertyValueActionExecuter.PARAM_VALUE;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.junit.Test;
@Experimental
public class ActionTest
{
private static final String ACTION_DEFINITION_NAME = "actionDefName";
private static final Map<String, Serializable> parameters = new HashMap<>();
static
{
parameters.put(PARAM_PROPERTY, "propertyName");
parameters.put(PARAM_VALUE, "propertyValue");
}
@Test
public void testFrom()
{
final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, "ruleId");
final org.alfresco.service.cmr.action.Action actionModel = new ActionImpl(nodeRef, "actionId", ACTION_DEFINITION_NAME, parameters);
final Action expectedAction = Action.builder().actionDefinitionId(ACTION_DEFINITION_NAME).params(parameters).create();
final Action actualAction = Action.from(actionModel);
assertThat(actualAction).isNotNull().usingRecursiveComparison().isEqualTo(expectedAction);
}
@Test
public void testFromActionModelWithNullValues()
{
final org.alfresco.service.cmr.action.Action actionModel = new ActionImpl(null, null, null);
final Action expectedAction = Action.builder().params(Collections.emptyMap()).create();
final Action actualAction = Action.from(actionModel);
assertThat(actualAction).isNotNull().usingRecursiveComparison().isEqualTo(expectedAction);
}
}

View File

@@ -0,0 +1,180 @@
/*
* #%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.model.rules;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.action.ActionConditionImpl;
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.ActionCondition;
import org.junit.Test;
@Experimental
public class CompositeConditionTest
{
@Test
public void testFrom()
{
final List<ActionCondition> actionConditions = List.of(
createActionCondition("value1"),
createActionCondition("value2", true),
createActionCondition("value3")
);
final CompositeCondition expectedCompositeCondition = createCompositeCondition(List.of(
createCompositeCondition(false, List.of(
createSimpleCondition("value1"),
createSimpleCondition("value3")
)),
createCompositeCondition(true, List.of(
createSimpleCondition("value2")
))
));
// when
final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions);
assertThat(actualCompositeCondition).isNotNull().usingRecursiveComparison().isEqualTo(expectedCompositeCondition);
}
@Test
public void testFromEmptyList()
{
final List<ActionCondition> actionConditions = Collections.emptyList();
final CompositeCondition expectedCompositeCondition = CompositeCondition.builder().create();
// when
final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions);
assertThat(actualCompositeCondition).isNotNull().usingRecursiveComparison().isEqualTo(expectedCompositeCondition);
}
@Test
public void testFromNullValue()
{
// when
final CompositeCondition actualCompositeCondition = CompositeCondition.from(null);
assertThat(actualCompositeCondition).isNull();
}
@Test
public void testFromListContainingNull()
{
final List<ActionCondition> actionConditions = new ArrayList<>();
actionConditions.add(null);
final CompositeCondition expectedCompositeCondition = CompositeCondition.builder().create();
// when
final CompositeCondition actualCompositeCondition = CompositeCondition.from(actionConditions);
assertThat(actualCompositeCondition).isNotNull().usingRecursiveComparison().isEqualTo(expectedCompositeCondition);
}
@Test
public void testOfSimpleConditions()
{
final List<SimpleCondition> simpleConditions = List.of(SimpleCondition.builder().field("field").comparator("comparator").parameter("param").create());
final boolean inverted = true;
final ConditionOperator conditionOperator = ConditionOperator.OR;
final CompositeCondition expectedCondition = createCompositeCondition(inverted, conditionOperator, null, simpleConditions);
// when
final CompositeCondition actualCompositeCondition = CompositeCondition.ofSimpleConditions(simpleConditions, inverted, conditionOperator);
assertThat(actualCompositeCondition).isNotNull().usingRecursiveComparison().isEqualTo(expectedCondition);
}
@Test
public void testOfEmptySimpleConditions()
{
// when
final CompositeCondition actualCompositeCondition = CompositeCondition.ofSimpleConditions(Collections.emptyList(), false, ConditionOperator.AND);
assertThat(actualCompositeCondition).isNull();
}
@Test
public void testOfNullSimpleConditions()
{
// when
final CompositeCondition actualCompositeCondition = CompositeCondition.ofSimpleConditions(null, false, ConditionOperator.AND);
assertThat(actualCompositeCondition).isNull();
}
private static ActionCondition createActionCondition(final String value)
{
return createActionCondition(value, false);
}
private static ActionCondition createActionCondition(final String value, final boolean inverted)
{
final ActionCondition actionCondition = new ActionConditionImpl("fake-id", ComparePropertyValueEvaluator.NAME);
actionCondition.setInvertCondition(inverted);
final Map<String, Serializable> parameterValues = new HashMap<>();
parameterValues.put(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY, "content-property");
parameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, "operation");
parameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, value);
actionCondition.setParameterValues(parameterValues);
return actionCondition;
}
private static SimpleCondition createSimpleCondition(final String value) {
return SimpleCondition.builder()
.field("content-property")
.comparator("operation")
.parameter(value)
.create();
}
private static CompositeCondition createCompositeCondition(final List<CompositeCondition> compositeConditions) {
return createCompositeCondition(false, ConditionOperator.AND, compositeConditions, null);
}
private static CompositeCondition createCompositeCondition(final boolean inverted, final List<SimpleCondition> simpleConditions) {
return createCompositeCondition(inverted, ConditionOperator.AND, null, simpleConditions);
}
private static CompositeCondition createCompositeCondition(final boolean inverted, final ConditionOperator conditionOperator,
final List<CompositeCondition> compositeConditions, final List<SimpleCondition> simpleConditions) {
return CompositeCondition.builder()
.inverted(inverted)
.booleanMode(conditionOperator)
.compositeConditions(compositeConditions)
.simpleConditions(simpleConditions)
.create();
}
}

View File

@@ -27,22 +27,27 @@
package org.alfresco.rest.api.model.rules;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
import java.util.Collections;
import java.util.List;
import org.alfresco.repo.action.ActionConditionImpl;
import org.alfresco.repo.action.ActionImpl;
import org.alfresco.repo.action.executer.ScriptActionExecuter;
import org.alfresco.rest.api.Nodes;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.Action;
import org.alfresco.service.cmr.action.ActionCondition;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.rule.RuleType;
import org.assertj.core.api.Condition;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@Experimental
@RunWith(MockitoJUnitRunner.class)
public class RuleTest
{
private static final String RULE_ID = "fake-rule-id";
@@ -50,8 +55,9 @@ public class RuleTest
private static final String RULE_DESCRIPTION = "rule description";
private static final boolean RULE_ENABLED = true;
private static final boolean RULE_CASCADE = true;
private static final boolean RULE_ASYNC = false;
private static final boolean RULE_ASYNC = true;
private static final boolean RULE_SHARED = true;
private static final String ACTION_DEFINITION_NAME = "action-def-name";
private static final String ERROR_SCRIPT = "error-script-ref";
@Test
@@ -61,7 +67,7 @@ public class RuleTest
final Rule expectedRule = createRuleWithDefaultValues();
// when
final Rule actualRule = Rule.from(ruleModel, RULE_SHARED);
final Rule actualRule = Rule.from(ruleModel);
assertThat(actualRule).isNotNull().usingRecursiveComparison().isEqualTo(expectedRule);
@@ -74,12 +80,57 @@ public class RuleTest
final Rule expectedRule = Rule.builder().enabled(true).create();
// when
final Rule actualRule = Rule.from(ruleModel, false);
final Rule actualRule = Rule.from(ruleModel);
assertThat(actualRule).isNotNull().usingRecursiveComparison().isEqualTo(expectedRule);
}
@Test
public void testToServiceModel()
{
final Nodes nodesMock = mock(Nodes.class);
final Rule rule = createRuleWithDefaultValues();
rule.setActions(List.of(Action.builder().actionDefinitionId(ACTION_DEFINITION_NAME).create()));
final org.alfresco.service.cmr.rule.Rule expectedRuleModel = createRuleModel();
final org.alfresco.service.cmr.action.Action expectedCompensatingActionModel = createCompensatingActionModel();
// when
final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock);
then(nodesMock).should().validateOrLookupNode(RULE_ID, null);
then(nodesMock).shouldHaveNoMoreInteractions();
assertThat(actualRuleModel)
.isNotNull()
.usingRecursiveComparison().ignoringFields("nodeRef", "action")
.isEqualTo(expectedRuleModel);
assertThat(actualRuleModel.getAction())
.isNotNull();
assertThat(actualRuleModel.getAction().getCompensatingAction())
.isNotNull()
.usingRecursiveComparison().ignoringFields("id")
.isEqualTo(expectedCompensatingActionModel);
}
@Test
public void testToServiceModel_withNullValues()
{
final Nodes nodesMock = mock(Nodes.class);
final Rule rule = new Rule();
final org.alfresco.service.cmr.rule.Rule expectedRuleModel = new org.alfresco.service.cmr.rule.Rule();
expectedRuleModel.setRuleDisabled(true);
// when
final org.alfresco.service.cmr.rule.Rule actualRuleModel = rule.toServiceModel(nodesMock);
then(nodesMock).shouldHaveNoInteractions();
assertThat(actualRuleModel)
.isNotNull()
.usingRecursiveComparison()
.ignoringFields("ruleTypes")
.isEqualTo(expectedRuleModel);
}
private static org.alfresco.service.cmr.rule.Rule createRuleModel() {
final NodeRef nodeRef = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, RULE_ID);
final org.alfresco.service.cmr.rule.Rule ruleModel = new org.alfresco.service.cmr.rule.Rule(nodeRef);
@@ -89,17 +140,27 @@ public class RuleTest
ruleModel.applyToChildren(RULE_CASCADE);
ruleModel.setExecuteAsynchronously(RULE_ASYNC);
ruleModel.setRuleTypes(List.of(RuleType.INBOUND, RuleType.UPDATE));
final Action compensatingAction = new ActionImpl(nodeRef, "compensatingActionId", "compensatingActionDefName");
compensatingAction.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, ERROR_SCRIPT);
final ActionCondition actionCondition = new ActionConditionImpl("actionConditionId", "actionConditionDefName");
final Action action = new ActionImpl(nodeRef, "actionId", "actionDefName");
action.setCompensatingAction(compensatingAction);
action.addActionCondition(actionCondition);
ruleModel.setAction(action);
ruleModel.setAction(createActionModel());
return ruleModel;
}
private static org.alfresco.service.cmr.action.Action createActionModel() {
final ActionCondition actionCondition = new ActionConditionImpl("action-condition-id", "action-condition-def-name");
final org.alfresco.service.cmr.action.Action actionModel = new ActionImpl(null, "action-id", ACTION_DEFINITION_NAME);
actionModel.setCompensatingAction(createCompensatingActionModel());
actionModel.addActionCondition(actionCondition);
return actionModel;
}
private static org.alfresco.service.cmr.action.Action createCompensatingActionModel() {
final org.alfresco.service.cmr.action.Action compensatingActionModel = new ActionImpl(null, "compensating-action-id", ScriptActionExecuter.NAME);
compensatingActionModel.setParameterValue(ScriptActionExecuter.PARAM_SCRIPTREF, ERROR_SCRIPT);
return compensatingActionModel;
}
private static Rule createRuleWithDefaultValues() {
return Rule.builder()
.id(RULE_ID)
@@ -108,9 +169,9 @@ public class RuleTest
.enabled(RULE_ENABLED)
.cascade(RULE_CASCADE)
.asynchronous(RULE_ASYNC)
.shared(RULE_SHARED)
.triggers(List.of(RuleTrigger.INBOUND, RuleTrigger.UPDATE))
.errorScript(ERROR_SCRIPT)
.conditions(CompositeCondition.from(Collections.emptyList()))
.create();
}
}

View File

@@ -0,0 +1,213 @@
/*
* #%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.model.rules;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.alfresco.repo.action.ActionConditionImpl;
import org.alfresco.repo.action.evaluator.CompareMimeTypeEvaluator;
import org.alfresco.repo.action.evaluator.ComparePropertyValueEvaluator;
import org.alfresco.repo.action.evaluator.HasAspectEvaluator;
import org.alfresco.repo.action.evaluator.HasChildEvaluator;
import org.alfresco.repo.action.evaluator.HasTagEvaluator;
import org.alfresco.repo.action.evaluator.HasVersionHistoryEvaluator;
import org.alfresco.repo.action.evaluator.InCategoryEvaluator;
import org.alfresco.repo.action.evaluator.IsSubTypeEvaluator;
import org.alfresco.repo.action.evaluator.NoConditionEvaluator;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.action.ActionCondition;
import org.junit.Test;
@Experimental
public class SimpleConditionTest
{
private static List<TestData> getTestData() {
return List.of(
TestData.of(ComparePropertyValueEvaluator.NAME),
TestData.of(CompareMimeTypeEvaluator.NAME),
TestData.of(HasAspectEvaluator.NAME),
TestData.of(HasChildEvaluator.NAME),
TestData.of(HasTagEvaluator.NAME),
TestData.of(HasVersionHistoryEvaluator.NAME),
TestData.of(InCategoryEvaluator.NAME),
TestData.of(IsSubTypeEvaluator.NAME),
TestData.of(NoConditionEvaluator.NAME, true),
TestData.of("fake-definition-name", true),
TestData.of("", true),
TestData.of(null, true)
);
}
@Test
public void testFrom()
{
for (TestData testData : getTestData())
{
final ActionCondition actionCondition = createActionCondition(testData.actionDefinitionName);
// when
final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition);
assertThat(Objects.isNull(actualSimpleCondition)).isEqualTo(testData.isNullResult);
if (!testData.isNullResult)
{
assertThat(actualSimpleCondition.getField()).isNotEmpty();
assertThat(actualSimpleCondition.getComparator()).isNotEmpty();
assertThat(actualSimpleCondition.getParameter()).isNotEmpty();
}
}
}
@Test
public void testFromNullValue()
{
// when
final SimpleCondition actualSimpleCondition = SimpleCondition.from(null);
assertThat(actualSimpleCondition).isNull();
}
@Test
public void testFromActionConditionWithoutDefinitionName()
{
final ActionCondition actionCondition = new ActionConditionImpl("fake-id", null, createParameterValues());
// when
final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition);
assertThat(actualSimpleCondition).isNull();
}
@Test
public void testFromActionConditionWithoutParameterValues()
{
final ActionCondition actionCondition = new ActionConditionImpl("fake-id", "fake-def-name", null);
// when
final SimpleCondition actualSimpleCondition = SimpleCondition.from(actionCondition);
assertThat(actualSimpleCondition).isNull();
}
@Test
public void testListOf()
{
final List<ActionCondition> actionConditions = List.of(
createActionCondition(ComparePropertyValueEvaluator.NAME),
createActionCondition(CompareMimeTypeEvaluator.NAME)
);
final List<SimpleCondition> expectedSimpleConditions = List.of(
SimpleCondition.builder().field("content-property").comparator("operation").parameter("value").create(),
SimpleCondition.builder().field("property").comparator("equals").parameter("value").create()
);
// when
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(actionConditions);
assertThat(actualSimpleConditions)
.isNotNull()
.containsExactlyElementsOf(expectedSimpleConditions);
}
@Test
public void testListOfEmptyActionConditions()
{
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(Collections.emptyList());
assertThat(actualSimpleConditions).isNull();
}
@Test
public void testListOfNullActionConditions()
{
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(null);
assertThat(actualSimpleConditions).isNull();
}
@Test
public void testListOfActionConditionsContainingNull()
{
final List<ActionCondition> actionConditions = new ArrayList<>();
actionConditions.add(null);
final List<SimpleCondition> actualSimpleConditions = SimpleCondition.listOf(actionConditions);
assertThat(actualSimpleConditions).isNotNull().isEmpty();
}
private static ActionCondition createActionCondition(final String actionDefinitionName)
{
return new ActionConditionImpl("fake-id", actionDefinitionName, createParameterValues());
}
private static Map<String, Serializable> createParameterValues() {
final Map<String, Serializable> parameterValues = new HashMap<>();
parameterValues.put(ComparePropertyValueEvaluator.PARAM_CONTENT_PROPERTY, "content-property");
parameterValues.put(HasChildEvaluator.PARAM_ASSOC_TYPE, "assoc-type");
parameterValues.put(ComparePropertyValueEvaluator.PARAM_PROPERTY, "property");
parameterValues.put(ComparePropertyValueEvaluator.PARAM_OPERATION, "operation");
parameterValues.put(ComparePropertyValueEvaluator.PARAM_VALUE, "value");
parameterValues.put(HasAspectEvaluator.PARAM_ASPECT, "aspect");
parameterValues.put(HasChildEvaluator.PARAM_ASSOC_NAME, "assoc-name");
parameterValues.put(HasTagEvaluator.PARAM_TAG, "tag");
parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_ASPECT, "category-aspect");
parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, "category-value");
parameterValues.put(IsSubTypeEvaluator.PARAM_TYPE, "type");
return parameterValues;
}
private static class TestData
{
String actionDefinitionName;
boolean isNullResult;
public TestData(String actionDefinitionName, boolean isNullResult)
{
this.actionDefinitionName = actionDefinitionName;
this.isNullResult = isNullResult;
}
public static TestData of(String actionDefinitionName) {
return new TestData(actionDefinitionName, false);
}
public static TestData of(String actionDefinitionName, boolean isNullResult) {
return new TestData(actionDefinitionName, isNullResult);
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* #%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.nodes;
import junit.framework.TestCase;
import org.alfresco.rest.api.RuleSets;
import org.alfresco.rest.api.model.rules.RuleSetLink;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.List;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class NodeRuleSetsRelationTest extends TestCase
{
private static final String FOLDER_NODE_ID = "dummy-folder-node-id";
private static final String LINK_TO_NODE_ID = "dummy-link-to-node-id";
@Mock
private RuleSets ruleSets;
@Mock
private Parameters parameters;
@InjectMocks
private NodeRuleSetLinksRelation nodeRuleSetLinksRelation;
@Test
public void shouldProperlyCreateLink()
{
RuleSetLink ruleSetLink = new RuleSetLink();
List<RuleSetLink> ruleResult = List.of(ruleSetLink);
RuleSetLink requestBody = new RuleSetLink();
requestBody.setId(LINK_TO_NODE_ID);
when(ruleSets.linkToRuleSet(FOLDER_NODE_ID, LINK_TO_NODE_ID)).thenReturn(ruleSetLink);
List<RuleSetLink> actual = nodeRuleSetLinksRelation.create(FOLDER_NODE_ID,List.of(requestBody), parameters);
Assert.assertEquals(ruleResult, actual);
}
}

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