Compare commits

..

329 Commits

Author SHA1 Message Date
alfresco-build
06d500311c [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-31 07:05:57 +00:00
alfresco-build
8d95ffc9ff [maven-release-plugin][skip ci] prepare release 23.3.0.86 2024-07-31 07:05:54 +00:00
varapathijanakiram
6e05d5d157 Merge pull request #2832 from Alfresco/feature/MNT-24400-Suggester-feature
Suggester feature in Share
2024-07-31 11:54:20 +05:30
vjanakiram
dfff72849d I have added bean 2024-07-29 21:17:30 +05:30
alfresco-build
d60172e860 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-28 00:07:08 +00:00
alfresco-build
3cac4e8206 [maven-release-plugin][skip ci] prepare release 23.3.0.85 2024-07-28 00:07:05 +00:00
Alfresco CI User
b35a64d14f [force] Force release for 2024-07-28. 2024-07-28 00:04:10 +00:00
alfresco-build
10e78191dd [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-25 21:03:12 +00:00
alfresco-build
6290c46d62 [maven-release-plugin][skip ci] prepare release 23.3.0.84 2024-07-25 21:03:09 +00:00
Tiago Salvado
8a61badabc [MNT-24513] Immutable user (IDS): allow to change enabled status (#2789)
* [MNT-24513] Immutable user: allow enabled status change

* [MNT-24513] Created 'allow.immutable.user.enabled.status.update' to control whether an immutabled user enabled status can be changed or not

* [MNT-24513] Regardless user details enabled status, the person nodeRef enabled status is also checked

* [MNT-24513] Prevent LDAP users from being disabled. Changed variable name.
2024-07-25 21:23:51 +01:00
alfresco-build
f9946827c4 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-24 13:18:42 +00:00
alfresco-build
b812c7856e [maven-release-plugin][skip ci] prepare release 23.3.0.83 2024-07-24 13:18:40 +00:00
Eva Vasques
a3f6e13a7c MNT-24503 - FixedAclUpdater Job - Skip count if maxSize is set (#2809) 2024-07-24 13:40:50 +01:00
alfresco-build
afffc7e870 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-24 05:54:22 +00:00
alfresco-build
fe5a01e2bd [maven-release-plugin][skip ci] prepare release 23.3.0.82 2024-07-24 05:54:20 +00:00
purusothaman-mm
03625565e9 [MNT-24292] fix for delete vulnerability (#2806) 2024-07-24 10:45:14 +05:30
alfresco-build
8d1d2b4f1b [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-23 11:55:48 +00:00
alfresco-build
1342c6a7bb [maven-release-plugin][skip ci] prepare release 23.3.0.81 2024-07-23 11:55:45 +00:00
Tom Page
17152b69fc Merge pull request #2807 from Alfresco/feature/PMD730
[skip tests] Upgrade ya-pmd-scan.
2024-07-23 12:43:50 +01:00
Tom Page
1a7027327e [skip tests] PRODENG-291 Upgrade ya-pmd-scan. 2024-07-23 12:17:46 +01:00
alfresco-build
7921969222 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-21 00:07:02 +00:00
alfresco-build
9cc93de7b2 [maven-release-plugin][skip ci] prepare release 23.3.0.80 2024-07-21 00:07:00 +00:00
Alfresco CI User
55c9cf3407 [force] Force release for 2024-07-21. 2024-07-21 00:04:10 +00:00
alfresco-build
120f45ba92 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-19 09:04:23 +00:00
alfresco-build
eacdbd3770 [maven-release-plugin][skip ci] prepare release 23.3.0.79 2024-07-19 09:04:21 +00:00
dependabot[bot]
93d4701d80 Bump dependency.cxf.version from 4.0.4 to 4.0.5 (#2794)
Bumps `dependency.cxf.version` from 4.0.4 to 4.0.5.

Updates `org.apache.cxf:cxf-rt-frontend-jaxws` from 4.0.4 to 4.0.5

Updates `org.apache.cxf:cxf-rt-frontend-jaxrs` from 4.0.4 to 4.0.5

Updates `org.apache.cxf:cxf-rt-rs-client` from 4.0.4 to 4.0.5

Updates `org.apache.cxf:cxf-rt-transports-http` from 4.0.4 to 4.0.5

Updates `org.apache.cxf:cxf-rt-ws-policy` from 4.0.4 to 4.0.5

---
updated-dependencies:
- dependency-name: org.apache.cxf:cxf-rt-frontend-jaxws
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.cxf:cxf-rt-frontend-jaxrs
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.cxf:cxf-rt-rs-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.cxf:cxf-rt-transports-http
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.cxf:cxf-rt-ws-policy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-19 10:22:28 +02:00
alfresco-build
64baf03818 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-18 08:49:23 +00:00
alfresco-build
e39606aec5 [maven-release-plugin][skip ci] prepare release 23.3.0.78 2024-07-18 08:49:21 +00:00
Manish Kumar
7581e07c3c Merge pull request #2790 from Alfresco/fix/PRODSEC-8922-XSS
[PRODSEC-8922] fix xss vulnerability
2024-07-18 13:41:30 +05:30
alfresco-build
a01d375e6f [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-17 11:25:21 +00:00
alfresco-build
a98f44803a [maven-release-plugin][skip ci] prepare release 23.3.0.77 2024-07-17 11:25:19 +00:00
SathishK-T
cabc38b386 [MNT-24137] Audit Issue Internal Server Error fix (#2786)
* [MNT-24137][ags][tas] Audit Bug Fix

* [MNT-24137][ags][tas] Audit Bug Fix

* [MNT-24137][ags][tas] Audit Bug Fix

* [MNT-24137][ags][tas] Audit Bug Fix

* [MNT-24137][ags][tas] Audit Bug Fix

* [MNT-24137][ags][tas] Audit Bug Fix

* [MNT-24137][ags][tas] Audit Bug Fix

---------

Co-authored-by: Sathish Kumar <ST28@ford.com>
2024-07-17 16:19:19 +05:30
Eva Vasques
9ed29967b7 MNT-24503 - Limits on FixedAclUpdater (#2788)
* Limit the job execution to a configurable amount of nodes (system.fixedACLsUpdater.maxItems)
    * Add query template select_NodesWithAspectIds_Limited that does a left join with alf_store and limits the results
    * Query executions by the job are now limited to maxItemBatchSize
    * Imposing the order by in the query is now configurable (system.fixedACLsUpdater.orderNodes)
2024-07-17 11:47:06 +01:00
alfresco-build
b63a3eae9b [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-17 10:20:52 +00:00
alfresco-build
1ce46c2039 [maven-release-plugin][skip ci] prepare release 23.3.0.76 2024-07-17 10:20:50 +00:00
Suneet Gupta
278aa59302 [MNT-24310] Fix AGS Rest API returning non RM objects (#2787)
* [MNT-24310] Fix AGS Rest API returning non RM objects

* [MNT-24310] Fix AGS Rest API returning non RM objects

* [MNT-24310] Fix AGS Rest API returning non RM objects

* [MNT-24310] Fix AGS Rest API returning non RM objects

* [MNT-24310] Fix AGS Rest API returning non RM objects
2024-07-17 15:14:57 +05:30
Manish Kumar
51a51ecd6b [PRODSEC-8922] fix xss vulnerability 2024-07-17 13:52:19 +05:30
alfresco-build
10f4b10ae8 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-15 16:37:35 +00:00
alfresco-build
24575c436e [maven-release-plugin][skip ci] prepare release 23.3.0.75 2024-07-15 16:37:33 +00:00
Manish Kumar
25c4b677de [PRODSEC-9364] added java-uuid-generator (#2778)
* [PRODSEC-9364] added java-uuid-generator

* [PRODSEC-9364] addressed formatting issues

* [PRODSEC-9364] removed unnecessary qualifier java.util

* [PRODSEC-9364] removed addition import and change year in header
2024-07-15 21:29:09 +05:30
alfresco-build
6f13f36c5a [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-15 09:02:19 +00:00
alfresco-build
db8b353fb1 [maven-release-plugin][skip ci] prepare release 23.3.0.74 2024-07-15 09:02:17 +00:00
Wojtek Świętoń
2ccdee122a ACS-8394 ReportPortal Integration run only on master, as an optional step 2024-07-15 10:22:29 +02:00
alfresco-build
14c1b91a9b [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-14 00:06:55 +00:00
alfresco-build
5b562edad1 [maven-release-plugin][skip ci] prepare release 23.3.0.73 2024-07-14 00:06:53 +00:00
Alfresco CI User
19e577383a [force] Force release for 2024-07-14. 2024-07-14 00:03:41 +00:00
alfresco-build
115997d367 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-12 11:42:17 +00:00
alfresco-build
de2effcefb [maven-release-plugin][skip ci] prepare release 23.3.0.72 2024-07-12 11:42:15 +00:00
Piotr Żurek
79b78448e0 ACS-8323 Switch to defaults from properties (#2776) 2024-07-12 11:31:06 +02:00
alfresco-build
05c4f2282e [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-12 08:51:41 +00:00
alfresco-build
228944c59c [maven-release-plugin][skip ci] prepare release 23.3.0.71 2024-07-12 08:51:39 +00:00
Domenico Sibilio
ec279bcd5d [skip tests] 2024-07-12 10:48:59 +02:00
Domenico Sibilio
97770fd831 Rollback Jackson from 2.17.2 to 2.15.2 (#2777) 2024-07-12 10:10:45 +02:00
alfresco-build
1a99c54074 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-11 15:54:05 +00:00
alfresco-build
b30b7bd252 [maven-release-plugin][skip ci] prepare release 23.3.0.70 2024-07-11 15:54:01 +00:00
dependabot[bot]
7ce9183360 Bump org.codehaus.groovy:groovy-json from 3.0.19 to 3.0.22 (#2734)
Bumps [org.codehaus.groovy:groovy-json](https://github.com/apache/groovy) from 3.0.19 to 3.0.22.
- [Commits](https://github.com/apache/groovy/commits)

---
updated-dependencies:
- dependency-name: org.codehaus.groovy:groovy-json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-11 17:15:58 +02:00
dependabot[bot]
06af664a16 Bump dependency.camel.version from 4.0.0 to 4.6.0 (#2640)
Bumps `dependency.camel.version` from 4.0.0 to 4.6.0.

Updates `org.apache.camel:camel-activemq` from 4.0.0 to 4.6.0

Updates `org.apache.camel:camel-core` from 4.0.0 to 4.6.0

Updates `org.apache.camel:camel-spring-xml` from 4.0.0 to 4.6.0

Updates `org.apache.camel:camel-amqp` from 4.0.0 to 4.6.0

Updates `org.apache.camel:camel-jackson` from 4.0.0 to 4.6.0

Updates `org.apache.camel:camel-direct` from 4.0.0 to 4.6.0

Updates `org.apache.camel:camel-management` from 4.0.0 to 4.6.0

Updates `org.apache.camel:camel-mock` from 4.0.0 to 4.6.0

---
updated-dependencies:
- dependency-name: org.apache.camel:camel-activemq
  dependency-type: direct:production
  update-type: version-update:semver-minor
- 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-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-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>
2024-07-11 16:51:14 +02:00
alfresco-build
7adf58d35f [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-11 12:23:08 +00:00
alfresco-build
08e42ed877 [maven-release-plugin][skip ci] prepare release 23.3.0.69 2024-07-11 12:23:06 +00:00
Domenico Sibilio
aa2fb35b41 [skip tests] 2024-07-11 14:20:24 +02:00
Domenico Sibilio
ab1e762a65 Exclude jakarta.transaction-api from commons-dbcp2 (#2772) 2024-07-11 13:45:00 +02:00
Piotr Żurek
c6201fa2fa ACS-8323 Extend the possibility to configure the event sending strategy (#2765) 2024-07-11 12:56:45 +02:00
alfresco-build
0ab31fcc93 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-10 16:33:54 +00:00
alfresco-build
7616781ce9 [maven-release-plugin][skip ci] prepare release 23.3.0.68 2024-07-10 16:33:51 +00:00
dependabot[bot]
a7c83b9acc Bump org.codehaus.mojo:aspectj-maven-plugin from 1.14.0 to 1.15.0 (#2368)
Bumps [org.codehaus.mojo:aspectj-maven-plugin](https://github.com/mojohaus/aspectj-maven-plugin) from 1.14.0 to 1.15.0.
- [Release notes](https://github.com/mojohaus/aspectj-maven-plugin/releases)
- [Commits](https://github.com/mojohaus/aspectj-maven-plugin/compare/aspectj-maven-plugin-1.14.0...aspectj-maven-plugin-1.15.0)

---
updated-dependencies:
- dependency-name: org.codehaus.mojo:aspectj-maven-plugin
  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>
2024-07-10 17:05:30 +02:00
dependabot[bot]
a09649c40a --- (#2659)
updated-dependencies:
- dependency-name: com.google.code.gson:gson
  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>
2024-07-10 16:57:12 +02:00
dependabot[bot]
0bb0e5b5b0 Bump jakarta.json:jakarta.json-api from 2.1.2 to 2.1.3 (#2267)
Bumps [jakarta.json:jakarta.json-api](https://github.com/eclipse-ee4j/jsonp) from 2.1.2 to 2.1.3.
- [Release notes](https://github.com/eclipse-ee4j/jsonp/releases)
- [Commits](https://github.com/eclipse-ee4j/jsonp/commits)

---
updated-dependencies:
- dependency-name: jakarta.json:jakarta.json-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:56:45 +02:00
dependabot[bot]
0f1ef341f6 Bump org.awaitility:awaitility from 4.2.0 to 4.2.1 (#2515)
Bumps [org.awaitility:awaitility](https://github.com/awaitility/awaitility) from 4.2.0 to 4.2.1.
- [Changelog](https://github.com/awaitility/awaitility/blob/master/changelog.txt)
- [Commits](https://github.com/awaitility/awaitility/compare/awaitility-4.2.0...awaitility-4.2.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:51:06 +02:00
dependabot[bot]
48e4d8a5a6 Bump org.slf4j:slf4j-api from 2.0.9 to 2.0.13 (#2587)
Bumps org.slf4j:slf4j-api from 2.0.9 to 2.0.13.

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:50:00 +02:00
dependabot[bot]
22bd945003 Bump com.ibm.icu:icu4j from 73.2 to 75.1 (#2595)
Bumps [com.ibm.icu:icu4j](https://github.com/unicode-org/icu) from 73.2 to 75.1.
- [Release notes](https://github.com/unicode-org/icu/releases)
- [Commits](https://github.com/unicode-org/icu/commits)

---
updated-dependencies:
- dependency-name: com.ibm.icu:icu4j
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:49:35 +02:00
dependabot[bot]
12b986373e Bump jakarta.jms:jakarta.jms-api from 3.0.0 to 3.1.0 (#2131)
Bumps jakarta.jms:jakarta.jms-api from 3.0.0 to 3.1.0.

---
updated-dependencies:
- dependency-name: jakarta.jms:jakarta.jms-api
  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>
2024-07-10 16:47:24 +02:00
dependabot[bot]
fbc5b738ab Bump com.sun.xml.fastinfoset:FastInfoset from 2.1.0 to 2.1.1 (#2265)
Bumps com.sun.xml.fastinfoset:FastInfoset from 2.1.0 to 2.1.1.

---
updated-dependencies:
- dependency-name: com.sun.xml.fastinfoset:FastInfoset
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:47:00 +02:00
dependabot[bot]
92c1b2fb9d Bump org.mybatis:mybatis-spring from 3.0.2 to 3.0.3 (#2330)
Bumps [org.mybatis:mybatis-spring](https://github.com/mybatis/spring) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/mybatis/spring/releases)
- [Commits](https://github.com/mybatis/spring/compare/mybatis-spring-3.0.2...mybatis-spring-3.0.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:46:16 +02:00
dependabot[bot]
ca3a7663a0 Bump org.apache.commons:commons-lang3 from 3.13.0 to 3.14.0 (#2335)
Bumps org.apache.commons:commons-lang3 from 3.13.0 to 3.14.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-lang3
  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>
2024-07-10 16:45:54 +02:00
dependabot[bot]
ae88784bdb Bump org.apache.commons:commons-email from 1.5 to 1.6.0 (#2386)
Bumps org.apache.commons:commons-email from 1.5 to 1.6.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-email
  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>
2024-07-10 16:44:34 +02:00
dependabot[bot]
4f03115b69 Bump org.jsoup:jsoup from 1.16.1 to 1.18.1 (#2770)
Bumps [org.jsoup:jsoup](https://github.com/jhy/jsoup) from 1.16.1 to 1.18.1.
- [Release notes](https://github.com/jhy/jsoup/releases)
- [Changelog](https://github.com/jhy/jsoup/blob/master/CHANGES.md)
- [Commits](https://github.com/jhy/jsoup/compare/jsoup-1.16.1...jsoup-1.18.1)

---
updated-dependencies:
- dependency-name: org.jsoup:jsoup
  dependency-type: direct:development
  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>
2024-07-10 16:44:13 +02:00
dependabot[bot]
8fc2da1ce9 Bump org.apache.commons:commons-dbcp2 from 2.9.0 to 2.12.0 (#2486)
Bumps org.apache.commons:commons-dbcp2 from 2.9.0 to 2.12.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-dbcp2
  dependency-type: direct:development
  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>
2024-07-10 16:43:39 +02:00
dependabot[bot]
5f0c65b551 Bump dependency.jakarta-ee-jaxb-impl.version from 4.0.3 to 4.0.5 (#2494)
Bumps `dependency.jakarta-ee-jaxb-impl.version` from 4.0.3 to 4.0.5.

Updates `org.glassfish.jaxb:jaxb-runtime` from 4.0.3 to 4.0.5

Updates `org.glassfish.jaxb:jaxb-core` from 4.0.3 to 4.0.5

---
updated-dependencies:
- dependency-name: org.glassfish.jaxb:jaxb-runtime
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.glassfish.jaxb:jaxb-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:42:31 +02:00
dependabot[bot]
b3f5cf9f76 Bump jakarta.xml.bind:jakarta.xml.bind-api from 4.0.0 to 4.0.2 (#2495)
Bumps [jakarta.xml.bind:jakarta.xml.bind-api](https://github.com/jakartaee/jaxb-api) from 4.0.0 to 4.0.2.
- [Release notes](https://github.com/jakartaee/jaxb-api/releases)
- [Commits](https://github.com/jakartaee/jaxb-api/compare/4.0.0...4.0.2)

---
updated-dependencies:
- dependency-name: jakarta.xml.bind:jakarta.xml.bind-api
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:41:01 +02:00
dependabot[bot]
cb3934eb96 Bump org.apache.maven.plugins:maven-assembly-plugin from 3.6.0 to 3.7.1 (#2521)
Bumps [org.apache.maven.plugins:maven-assembly-plugin](https://github.com/apache/maven-assembly-plugin) from 3.6.0 to 3.7.1.
- [Release notes](https://github.com/apache/maven-assembly-plugin/releases)
- [Commits](https://github.com/apache/maven-assembly-plugin/compare/maven-assembly-plugin-3.6.0...maven-assembly-plugin-3.7.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-assembly-plugin
  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>
2024-07-10 16:38:44 +02:00
dependabot[bot]
df00db7cb7 Bump dependency.log4j.version from 2.20.0 to 2.23.1 (#2499)
Bumps `dependency.log4j.version` from 2.20.0 to 2.23.1.

Updates `org.apache.logging.log4j:log4j-slf4j2-impl` from 2.20.0 to 2.23.1

Updates `org.apache.logging.log4j:log4j-api` from 2.20.0 to 2.23.1

Updates `org.apache.logging.log4j:log4j-core` from 2.20.0 to 2.23.1

---
updated-dependencies:
- dependency-name: org.apache.logging.log4j:log4j-slf4j2-impl
  dependency-type: direct:development
  update-type: version-update:semver-minor
- dependency-name: org.apache.logging.log4j:log4j-api
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.logging.log4j:log4j-core
  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>
2024-07-10 16:37:30 +02:00
dependabot[bot]
af4e0c0a01 Bump dependency.cxf.version from 4.0.2 to 4.0.4 (#2505)
Bumps `dependency.cxf.version` from 4.0.2 to 4.0.4.

Updates `org.apache.cxf:cxf-rt-frontend-jaxws` from 4.0.2 to 4.0.4

Updates `org.apache.cxf:cxf-rt-frontend-jaxrs` from 4.0.2 to 4.0.4

Updates `org.apache.cxf:cxf-rt-rs-client` from 4.0.2 to 4.0.4

Updates `org.apache.cxf:cxf-rt-transports-http` from 4.0.2 to 4.0.4

Updates `org.apache.cxf:cxf-rt-ws-policy` from 4.0.2 to 4.0.4

---
updated-dependencies:
- dependency-name: org.apache.cxf:cxf-rt-frontend-jaxws
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.cxf:cxf-rt-frontend-jaxrs
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.cxf:cxf-rt-rs-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.cxf:cxf-rt-transports-http
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.apache.cxf:cxf-rt-ws-policy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:36:39 +02:00
dependabot[bot]
b6a56cb0f8 Bump org.apache.maven.plugins:maven-compiler-plugin (#2519)
Bumps [org.apache.maven.plugins:maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.11.0 to 3.13.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.11.0...maven-compiler-plugin-3.13.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  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>
2024-07-10 16:35:41 +02:00
dependabot[bot]
aac9be6887 Bump net.minidev:json-smart from 2.5.0 to 2.5.1 (#2532)
Bumps [net.minidev:json-smart](https://github.com/netplex/json-smart-v2) from 2.5.0 to 2.5.1.
- [Release notes](https://github.com/netplex/json-smart-v2/releases)
- [Commits](https://github.com/netplex/json-smart-v2/compare/2.5.0...2.5.1)

---
updated-dependencies:
- dependency-name: net.minidev:json-smart
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:35:08 +02:00
dependabot[bot]
c831a5e23d Bump org.eclipse.parsson:parsson from 1.1.4 to 1.1.6 (#2572)
Bumps [org.eclipse.parsson:parsson](https://github.com/eclipse-ee4j/parsson) from 1.1.4 to 1.1.6.
- [Release notes](https://github.com/eclipse-ee4j/parsson/releases)
- [Commits](https://github.com/eclipse-ee4j/parsson/compare/1.1.4...1.1.6)

---
updated-dependencies:
- dependency-name: org.eclipse.parsson:parsson
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:31:03 +02:00
dependabot[bot]
0e9633fa5b Bump commons-io:commons-io from 2.14.0 to 2.16.1 (#2575)
Bumps commons-io:commons-io from 2.14.0 to 2.16.1.

---
updated-dependencies:
- dependency-name: commons-io:commons-io
  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>
2024-07-10 16:30:04 +02:00
dependabot[bot]
971f8c9b46 Bump com.github.docker-java:docker-java from 3.3.2 to 3.3.6 (#2479)
Bumps [com.github.docker-java:docker-java](https://github.com/docker-java/docker-java) from 3.3.2 to 3.3.6.
- [Release notes](https://github.com/docker-java/docker-java/releases)
- [Changelog](https://github.com/docker-java/docker-java/blob/main/CHANGELOG.md)
- [Commits](https://github.com/docker-java/docker-java/compare/3.3.2...3.3.6)

---
updated-dependencies:
- dependency-name: com.github.docker-java:docker-java
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:27:35 +02:00
dependabot[bot]
cb89ed65fb Bump io.swagger:swagger-parser from 1.0.67 to 1.0.71 (#2621)
Bumps [io.swagger:swagger-parser](https://github.com/swagger-api/swagger-parser) from 1.0.67 to 1.0.71.
- [Release notes](https://github.com/swagger-api/swagger-parser/releases)
- [Commits](https://github.com/swagger-api/swagger-parser/compare/v1.0.67...v1.0.71)

---
updated-dependencies:
- dependency-name: io.swagger:swagger-parser
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:17:09 +02:00
dependabot[bot]
34357a83d8 Bump Alfresco/ya-pmd-scan from 3.0.0 to 3.0.2 (#2631)
Bumps [Alfresco/ya-pmd-scan](https://github.com/alfresco/ya-pmd-scan) from 3.0.0 to 3.0.2.
- [Release notes](https://github.com/alfresco/ya-pmd-scan/releases)
- [Commits](https://github.com/alfresco/ya-pmd-scan/compare/v3.0.0...v3.0.2)

---
updated-dependencies:
- dependency-name: Alfresco/ya-pmd-scan
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:16:14 +02:00
dependabot[bot]
b29afa2248 Bump dependency.aspectj.version from 1.9.20.1 to 1.9.22.1 (#2641)
Bumps `dependency.aspectj.version` from 1.9.20.1 to 1.9.22.1.

Updates `org.aspectj:aspectjrt` from 1.9.20.1 to 1.9.22.1
- [Release notes](https://github.com/eclipse/org.aspectj/releases)
- [Commits](https://github.com/eclipse/org.aspectj/commits)

Updates `org.aspectj:aspectjtools` from 1.9.20.1 to 1.9.22.1
- [Release notes](https://github.com/eclipse/org.aspectj/releases)
- [Commits](https://github.com/eclipse/org.aspectj/commits)

---
updated-dependencies:
- dependency-name: org.aspectj:aspectjrt
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.aspectj:aspectjtools
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:15:43 +02:00
dependabot[bot]
c89871c4fa Bump org.mockito:mockito-core from 5.4.0 to 5.12.0 (#2642)
Bumps [org.mockito:mockito-core](https://github.com/mockito/mockito) from 5.4.0 to 5.12.0.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v5.4.0...v5.12.0)

---
updated-dependencies:
- dependency-name: org.mockito:mockito-core
  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>
2024-07-10 16:14:16 +02:00
dependabot[bot]
2a07b65e25 Bump org.apache.commons:commons-compress from 1.26.0 to 1.26.2 (#2662)
Bumps org.apache.commons:commons-compress from 1.26.0 to 1.26.2.

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:13:33 +02:00
dependabot[bot]
36286e76e9 Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.5.0 to 3.7.0 (#2676)
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.5.0 to 3.7.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.5.0...maven-javadoc-plugin-3.7.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  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>
2024-07-10 16:12:56 +02:00
dependabot[bot]
267a776620 Bump org.apache.xmlbeans:xmlbeans from 5.2.0 to 5.2.1 (#2666)
Bumps org.apache.xmlbeans:xmlbeans from 5.2.0 to 5.2.1.

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:11:48 +02:00
dependabot[bot]
5da314f03a Bump commons-validator:commons-validator from 1.7 to 1.9.0 (#2671)
Bumps commons-validator:commons-validator from 1.7 to 1.9.0.

---
updated-dependencies:
- dependency-name: commons-validator:commons-validator
  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>
2024-07-10 16:11:23 +02:00
dependabot[bot]
02b43f42ef Bump com.google.guava:guava from 32.1.2-jre to 33.2.1-jre (#2674)
Bumps [com.google.guava:guava](https://github.com/google/guava) from 32.1.2-jre to 33.2.1-jre.
- [Release notes](https://github.com/google/guava/releases)
- [Commits](https://github.com/google/guava/commits)

---
updated-dependencies:
- dependency-name: com.google.guava:guava
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 16:10:24 +02:00
dependabot[bot]
1bcde87d42 Bump commons-net:commons-net from 3.9.0 to 3.11.1 (#2685)
Bumps commons-net:commons-net from 3.9.0 to 3.11.1.

---
updated-dependencies:
- dependency-name: commons-net:commons-net
  dependency-type: direct:development
  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>
2024-07-10 16:08:59 +02:00
dependabot[bot]
c06b210056 Bump org.apache.maven.plugins:maven-jar-plugin from 3.3.0 to 3.4.2 (#2703)
Bumps [org.apache.maven.plugins:maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 3.3.0 to 3.4.2.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-3.3.0...maven-jar-plugin-3.4.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-jar-plugin
  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>
2024-07-10 15:26:37 +02:00
dependabot[bot]
f4a89937ef Bump org.apache.maven.plugins:maven-dependency-plugin (#2707)
Bumps [org.apache.maven.plugins:maven-dependency-plugin](https://github.com/apache/maven-dependency-plugin) from 3.6.0 to 3.7.1.
- [Release notes](https://github.com/apache/maven-dependency-plugin/releases)
- [Commits](https://github.com/apache/maven-dependency-plugin/compare/maven-dependency-plugin-3.6.0...maven-dependency-plugin-3.7.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-dependency-plugin
  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>
2024-07-10 15:26:12 +02:00
dependabot[bot]
fc8c37b1e2 Bump commons-logging:commons-logging from 1.2 to 1.3.3 (#2740)
Bumps commons-logging:commons-logging from 1.2 to 1.3.3.

---
updated-dependencies:
- dependency-name: commons-logging:commons-logging
  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>
2024-07-10 15:23:12 +02:00
dependabot[bot]
fcc4bc9ac4 Bump org.eclipse.jetty:jetty-webapp from 11.0.16 to 11.0.22 (#2739)
Bumps org.eclipse.jetty:jetty-webapp from 11.0.16 to 11.0.22.

---
updated-dependencies:
- dependency-name: org.eclipse.jetty:jetty-webapp
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 15:22:50 +02:00
dependabot[bot]
8ee8be1696 Bump com.networknt:json-schema-validator from 1.0.86 to 1.5.0 (#2760)
Bumps [com.networknt:json-schema-validator](https://github.com/networknt/json-schema-validator) from 1.0.86 to 1.5.0.
- [Release notes](https://github.com/networknt/json-schema-validator/releases)
- [Changelog](https://github.com/networknt/json-schema-validator/blob/master/CHANGELOG.md)
- [Commits](https://github.com/networknt/json-schema-validator/compare/1.0.86...1.5.0)

---
updated-dependencies:
- dependency-name: com.networknt:json-schema-validator
  dependency-type: direct:development
  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>
2024-07-10 15:22:12 +02:00
dependabot[bot]
3aeb049d6b Bump dependency.rest-assured.version from 5.3.2 to 5.5.0 (#2761)
Bumps `dependency.rest-assured.version` from 5.3.2 to 5.5.0.

Updates `io.rest-assured:rest-assured` from 5.3.2 to 5.5.0
- [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt)
- [Commits](https://github.com/rest-assured/rest-assured/commits/rest-assured-5.5.0)

Updates `io.rest-assured:json-path` from 5.3.2 to 5.5.0
- [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt)
- [Commits](https://github.com/rest-assured/rest-assured/commits/rest-assured-5.5.0)

Updates `io.rest-assured:xml-path` from 5.3.2 to 5.5.0
- [Changelog](https://github.com/rest-assured/rest-assured/blob/master/changelog.txt)
- [Commits](https://github.com/rest-assured/rest-assured/commits/rest-assured-5.5.0)

Updates `io.rest-assured:json-schema-validator` from 5.3.2 to 5.5.0

---
updated-dependencies:
- dependency-name: io.rest-assured:rest-assured
  dependency-type: direct:development
  update-type: version-update:semver-minor
- dependency-name: io.rest-assured:json-path
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: io.rest-assured:xml-path
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: io.rest-assured:json-schema-validator
  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>
2024-07-10 15:21:39 +02:00
dependabot[bot]
2311665003 Bump dependency.jackson.version from 2.15.2 to 2.17.2 (#2759)
Bumps `dependency.jackson.version` from 2.15.2 to 2.17.2.

Updates `com.fasterxml.jackson.core:jackson-core` from 2.15.2 to 2.17.2
- [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.15.2...jackson-core-2.17.2)

Updates `com.fasterxml.jackson.core:jackson-databind` from 2.15.2 to 2.17.2
- [Commits](https://github.com/FasterXML/jackson/commits)

Updates `com.fasterxml.jackson.datatype:jackson-datatype-joda` from 2.15.2 to 2.17.2
- [Commits](https://github.com/FasterXML/jackson-datatype-joda/compare/jackson-datatype-joda-2.15.2...jackson-datatype-joda-2.17.2)

Updates `com.fasterxml.jackson.dataformat:jackson-dataformat-yaml` from 2.15.2 to 2.17.2
- [Commits](https://github.com/FasterXML/jackson-dataformats-text/compare/jackson-dataformats-text-2.15.2...jackson-dataformats-text-2.17.2)

Updates `com.fasterxml.jackson.core:jackson-annotations` from 2.15.2 to 2.17.2
- [Commits](https://github.com/FasterXML/jackson/commits)

Updates `com.fasterxml.jackson.module:jackson-module-jaxb-annotations` from 2.15.2 to 2.17.2
- [Commits](https://github.com/FasterXML/jackson-modules-base/compare/jackson-modules-base-2.15.2...jackson-modules-base-2.17.2)

---
updated-dependencies:
- dependency-name: com.fasterxml.jackson.core:jackson-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.fasterxml.jackson.core:jackson-databind
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-joda
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.fasterxml.jackson.dataformat:jackson-dataformat-yaml
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.fasterxml.jackson.core:jackson-annotations
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.fasterxml.jackson.module:jackson-module-jaxb-annotations
  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>
2024-07-10 15:21:02 +02:00
alfresco-build
90fad5d4e8 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-10 09:41:26 +00:00
alfresco-build
dee3674494 [maven-release-plugin][skip ci] prepare release 23.3.0.67 2024-07-10 09:41:24 +00:00
dependabot[bot]
91b91e3dee Bump org.projectlombok:lombok from 1.18.30 to 1.18.34 (#2729)
Bumps [org.projectlombok:lombok](https://github.com/projectlombok/lombok) from 1.18.30 to 1.18.34.
- [Changelog](https://github.com/projectlombok/lombok/blob/master/doc/changelog.markdown)
- [Commits](https://github.com/projectlombok/lombok/compare/v1.18.30...v1.18.34)

---
updated-dependencies:
- dependency-name: org.projectlombok:lombok
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 09:43:54 +02:00
dependabot[bot]
c085d42531 Bump org.codehaus.groovy:groovy from 3.0.19 to 3.0.22 (#2733)
Bumps [org.codehaus.groovy:groovy](https://github.com/apache/groovy) from 3.0.19 to 3.0.22.
- [Commits](https://github.com/apache/groovy/commits)

---
updated-dependencies:
- dependency-name: org.codehaus.groovy:groovy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 09:08:02 +02:00
dependabot[bot]
d0323836ad Bump org.codehaus.cargo:cargo-maven3-plugin from 1.10.9 to 1.10.14 (#2735)
Bumps org.codehaus.cargo:cargo-maven3-plugin from 1.10.9 to 1.10.14.

---
updated-dependencies:
- dependency-name: org.codehaus.cargo:cargo-maven3-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 09:07:35 +02:00
dependabot[bot]
628d299980 Bump org.apache.httpcomponents.core5:httpcore5 from 5.2.3 to 5.2.5 (#2736)
Bumps [org.apache.httpcomponents.core5:httpcore5](https://github.com/apache/httpcomponents-core) from 5.2.3 to 5.2.5.
- [Changelog](https://github.com/apache/httpcomponents-core/blob/rel/v5.2.5/RELEASE_NOTES.txt)
- [Commits](https://github.com/apache/httpcomponents-core/compare/rel/v5.2.3...rel/v5.2.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 09:06:59 +02:00
dependabot[bot]
b532ba9d54 Bump org.springframework.security:spring-security-bom (#2698)
Bumps [org.springframework.security:spring-security-bom](https://github.com/spring-projects/spring-security) from 6.3.0 to 6.3.1.
- [Release notes](https://github.com/spring-projects/spring-security/releases)
- [Changelog](https://github.com/spring-projects/spring-security/blob/main/RELEASE.adoc)
- [Commits](https://github.com/spring-projects/spring-security/compare/6.3.0...6.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 09:05:29 +02:00
dependabot[bot]
195f5b1a8c Bump org.assertj:assertj-core from 3.24.2 to 3.26.3 (#2769)
Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.24.2 to 3.26.3.
- [Release notes](https://github.com/assertj/assertj/releases)
- [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.24.2...assertj-build-3.26.3)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  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>
2024-07-10 09:04:41 +02:00
alfresco-build
c8718ca722 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-07 00:11:08 +00:00
alfresco-build
9a48b09f32 [maven-release-plugin][skip ci] prepare release 23.3.0.66 2024-07-07 00:11:06 +00:00
Alfresco CI User
3421bcb532 [force] Force release for 2024-07-07. 2024-07-07 00:03:55 +00:00
alfresco-build
e3175e9a98 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-04 16:22:54 +00:00
alfresco-build
f5c71e6098 [maven-release-plugin][skip ci] prepare release 23.3.0.65 2024-07-04 16:22:52 +00:00
Sara
725ef34ccb Merge pull request #2738 from Alfresco/feature/ACS-8294_Bump_SS-IE_to_2.0.11
ACS-8294 Bump SS/IE to 2.0.11
2024-07-04 16:44:24 +01:00
Sara Aspery
b7224b3d20 Bump SS/IE to 2.0.11 2024-07-04 13:51:50 +01:00
alfresco-build
24c6abedb5 [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-04 11:22:18 +00:00
alfresco-build
bf2f123aa7 [maven-release-plugin][skip ci] prepare release 23.3.0.64 2024-07-04 11:22:16 +00:00
Piotr Żurek
0e90fe9710 ACS-8289 Bump ATS (#2737) 2024-07-04 12:34:53 +02:00
alfresco-build
638058629d [maven-release-plugin][skip ci] prepare for next development iteration 2024-07-03 13:38:48 +00:00
alfresco-build
0e7660be83 [maven-release-plugin][skip ci] prepare release 23.3.0.63 2024-07-03 13:38:45 +00:00
SathishK-T
35b4ad5dbe [APPS-2905][APPS-2906][APPS-2907][APPS-2909] Defect fixes in Retention Schedule V1 API's (#2732)
* [APPS-2907][APPS-2909] Validation Changes in Retention Schedule V1 API

* [APPS-2907][APPS-2909] Defect fixes in Retention Schedule V1 API's

* [APPS-2907][APPS-2909] Defect fixes in Retention Schedule V1 API's

* [APPS-2907][APPS-2909] Defect fixes in Retention Schedule V1 API's

* [APPS-2907][APPS-2909] Defect fixes in Retention Schedule V1 API's

* [APPS-2907][APPS-2909] Defect fixes in Retention Schedule V1 API's

* [APPS-2907][APPS-2909] Defect fixes in Retention Schedule V1 API's

---------

Co-authored-by: Sathish Kumar <ST28@ford.com>
2024-07-03 18:32:42 +05:30
alfresco-build
90b91b87ef [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-30 00:06:31 +00:00
alfresco-build
bfce7cf3ad [maven-release-plugin][skip ci] prepare release 23.3.0.62 2024-06-30 00:06:29 +00:00
Alfresco CI User
03a261c4c5 [force] Force release for 2024-06-30. 2024-06-30 00:03:41 +00:00
alfresco-build
4b3558ff12 [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-28 12:32:43 +00:00
alfresco-build
4355add778 [maven-release-plugin][skip ci] prepare release 23.3.0.61 2024-06-28 12:32:41 +00:00
SathishK-T
92fbaf29d4 [APPS-2838][APPS-2839] POST and GET API implementation for the Retention Schedule Steps (#2721)
* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

* [APPS-2838][APPS-2839] Fixed Junit Testcases

* [APPS-2838][APPS-2839] Retention Schedule Step POST and GET API

---------

Co-authored-by: Sathish Kumar <ST28@ford.com>
Co-authored-by: suneet-gupta <suneet.gupta@hyland.com>
2024-06-28 17:26:17 +05:30
alfresco-build
8e15dba3eb [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-27 04:39:04 +00:00
alfresco-build
2206479e06 [maven-release-plugin][skip ci] prepare release 23.3.0.60 2024-06-27 04:39:02 +00:00
Suneet Gupta
abeaff52e8 [APPS-2019] Add Undeletable and Unmovable Aspects to Data Dictionary and its Level 1 sub-folders (#2705)
* [force] Force release for 2024-06-09.

* [APPS-2019] Added Undeletable and Unmovable Aspect to Data Dictionary Folder

* [APPS-2019] Added Undeletable and Unmovable Aspect to Data Dictionary Folder

* [APPS-2019] Added Undeletable and Unmovable Aspect to Data Dictionary Folder

* [APPS-2019] Added Undeletable and Unmovable Aspect to Data Dictionary Folder

* [APPS-2019] Added Undeletable and Unmovable Aspect to Data Dictionary Folder

* [APPS-2019] Added Undeletable and Unmovable Aspect to Data Dictionary Folder

* [APPS-2019] [ags] [tas] Added Integration Test Cases

* [APPS-2019] [ags] [tas] Added fix for restricting the move folder for Data Dictionary

* [APPS-2019] [ags] [tas] Added fix for restricting the move folder for Data Dictionary

* Added Undeletable and Unmovable Aspects to Data Dictionary Folder

* [APPS-2019] Updated Integration Test Cases

* [APPS-2019] [ags] [tas] Added fix for restricting the move folder for Data Dictionary

* [APPS-2019] [ags] [tas] Added fix for restricting the move folder for Data Dictionary

* [APPS-2019] [ags] [tas] Addressed review comments

* [APPS-2019] [ags] [tas] Addressed review comments

* [APPS-2019] [ags] [tas] Addressed review comments

* [APPS-2019] [ags] [tas] Addressed review comments

* [APPS-2019] [ags] [tas] Addressed review comments

* [APPS-2019] [ags] [tas] Addressed review comments

* [APPS-2019] [ags] [tas] Addressed review comments

* [APPS-2019] [ags] [tas] Addressed review comments

* [APPS-2019] [ags] [tas] Addressed review comments

* [APPS-2019] [ags] [tas] Addressed review comments

* [APPS-2019] [ags] [tas] Addressed review comments

---------

Co-authored-by: Alfresco CI User <build@alfresco.com>
2024-06-27 10:05:57 +05:30
alfresco-build
76be8d2bec [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-26 13:28:59 +00:00
alfresco-build
ce27304eae [maven-release-plugin][skip ci] prepare release 23.3.0.59 2024-06-26 13:28:56 +00:00
Damian Ujma
060cf3aa3c ACS-8048 Fix HXIAM access token validation issues (#2706)
* ACS-8047: WIP - Fixed HXIAM access token validation issues.

* ACS-8048 Accept at+jwt token + make signature algorithm configurable

* ACS-8048 Accept multiple signature algorithms

* ACS-8048 Fix PMD issue

* ACS-8048 Log using the default signature algorithm

* ACS-8048 Refactor

---------

Co-authored-by: Jamal Kaabi-Mofrad <jamal.kaabimofrad@alfresco.com>
2024-06-26 13:47:08 +02:00
SathishK-T
f1fdf72c5b [APPS-2836][APPS-2837] Retention Schedule POST and GET API (#2704)
* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

* [APPS-2836][APPS-2837] POST and GET API for Retention Schedule

---------

Co-authored-by: Sathish Kumar <ST28@ford.com>
2024-06-26 16:48:25 +05:30
alfresco-build
b580a52459 [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-25 14:45:09 +00:00
alfresco-build
d13da0cdfa [maven-release-plugin][skip ci] prepare release 23.3.0.58 2024-06-25 14:45:07 +00:00
SathishK-T
ca236d9814 [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs (#2672)
* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

* [APPS-2853] Swagger Documentation for Retention Schedule V1 APIs

---------

Co-authored-by: Sathish Kumar <ST28@ford.com>
2024-06-25 19:34:58 +05:30
alfresco-build
8398a5dca0 [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-23 00:06:44 +00:00
alfresco-build
52731727c6 [maven-release-plugin][skip ci] prepare release 23.3.0.57 2024-06-23 00:06:42 +00:00
Alfresco CI User
2f45231149 [force] Force release for 2024-06-23. 2024-06-23 00:03:45 +00:00
alfresco-build
447d0c4f56 [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-19 11:19:32 +00:00
alfresco-build
5e920054f4 [maven-release-plugin][skip ci] prepare release 23.3.0.56 2024-06-19 11:19:30 +00:00
Damian Ujma
2f66f068a6 ACS-7556 Bulk update in Legal Holds (#2692)
* ACS-7557 Add Legal Holds Bulk v1 API (#2624)

* ACS-7557 Add Legal Holds Bulk v1 API

* ACS-7557 Improve v1 API

* ACS-7557 Replace processId with bulkStatusId

* ACS-7587 Implement v1 Bulk API to add items to a hold (#2656)

* ACS-7557 Add bulk API design

* ACS-7557 Fix 

* ACS-7557 Add permissions checks 

* ACS-7557 Add IT tests

* ACS-7557 Add comments + logging

* ACS-7557 Refactor

* ACS-7557 Reimplement task container

* ACS-7557 Refactor code

* ACS-7587 Remove merge leftovers

* ACS-7587 Refactor 

* ACS-7587 Tests 

* ACS-7587 Change DefaultHoldBulkMonitor

* ACS-7587 Reimplement BulkStatusUpdater

* ACS-7587 Fix PMD issues

* ACS-7587 Fix PMD isues

* ACS-7587 Refactor

* ACS-7587 Add test files alternately

* ACS-7587 Refactor code

* ACS-7587 Improve search query

* ACS-7587 Fix PMD issues

* ACS-7587 Fix PMD issue

* ACS-7587 Fix intermittent failure

* ACS7587 Fix intermittent failure (#2681)

* ACS-7587 Implement bulk cancellations (#2683)
2024-06-19 12:44:07 +02:00
alfresco-build
2461b75f61 [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-19 10:27:46 +00:00
alfresco-build
96231517bd [maven-release-plugin][skip ci] prepare release 23.3.0.55 2024-06-19 10:27:44 +00:00
mikolajbrzezinski
b73b8df892 ACS-6931 Re-enable Veracode SAST Scan (#2690)
ACS-6931 Re-enable Veracode SAST Scan
2024-06-19 11:51:40 +02:00
alfresco-build
08e49c98dd [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-18 07:43:10 +00:00
alfresco-build
ba50617181 [maven-release-plugin][skip ci] prepare release 23.3.0.54 2024-06-18 07:43:08 +00:00
Sara
0d621badd7 Merge pull request #2696 from Alfresco/feature/MNT-24205_Bump_ATS_to_4.1.3-A2
MNT-24205 Bump t-core to 5.1.3-A3 and t-service to 4.1.3-A2
2024-06-18 08:07:03 +01:00
alfresco-build
661ddce806 [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-17 14:37:53 +00:00
alfresco-build
aa8b0256e1 [maven-release-plugin][skip ci] prepare release 23.3.0.53 2024-06-17 14:37:50 +00:00
tiagosalvado10
8990581cc1 MNT-24205 Bump t-core to 5.1.3-A3 and t-service to 4.1.3-A2 2024-06-17 14:56:44 +01:00
Kacper Magdziarz
04d76a182a Bump SS/IE to 2.0.11-A6 (#2694) 2024-06-17 15:20:02 +02:00
alfresco-build
27fbf633df [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-17 11:22:54 +00:00
alfresco-build
358ca8dc9e [maven-release-plugin][skip ci] prepare release 23.3.0.52 2024-06-17 11:22:51 +00:00
rrajoria
9a25862cc9 Update Aos alpha version 2024-06-17 16:05:53 +05:30
alfresco-build
ac7e58ddc5 [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-16 00:06:38 +00:00
alfresco-build
6bcaa1be04 [maven-release-plugin][skip ci] prepare release 23.3.0.51 2024-06-16 00:06:36 +00:00
Alfresco CI User
a1bf0f5480 [force] Force release for 2024-06-16. 2024-06-16 00:03:32 +00:00
alfresco-build
2c3d5dd297 [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-09 00:07:41 +00:00
alfresco-build
6b32d96f08 [maven-release-plugin][skip ci] prepare release 23.3.0.50 2024-06-09 00:07:38 +00:00
Alfresco CI User
69dd388133 [force] Force release for 2024-06-09. 2024-06-09 00:04:05 +00:00
alfresco-build
29106d307f [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-07 11:35:11 +00:00
alfresco-build
ef8b3578df [maven-release-plugin][skip ci] prepare release 23.3.0.49 2024-06-07 11:35:08 +00:00
Domenico Sibilio
dc5128b447 ACS-8114 Bump TAS utility to 5.0.1 (#2684) 2024-06-07 12:58:40 +02:00
alfresco-build
741ac97c3b [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-06 12:07:03 +00:00
alfresco-build
3f5cb68250 [maven-release-plugin][skip ci] prepare release 23.3.0.48 2024-06-06 12:07:00 +00:00
dependabot[bot]
fdb4f9e338 Bump org.springframework.security:spring-security-bom from 6.2.2 to 6.3.0 (#2658)
updated-dependencies:
- dependency-name: org.springframework.security:spring-security-bom
  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>
2024-06-06 13:29:18 +02:00
alfresco-build
f3f3a1db4b [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-05 16:18:58 +00:00
alfresco-build
eb922e1c95 [maven-release-plugin][skip ci] prepare release 23.3.0.47 2024-06-05 16:18:55 +00:00
Domenico Sibilio
46da34fabd ACS-8071 Bump bouncycastle to 1.78.1 (#2682) 2024-06-05 17:42:17 +02:00
alfresco-build
7dee8314fb [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-04 08:47:09 +00:00
alfresco-build
f888f8244e [maven-release-plugin][skip ci] prepare release 23.3.0.46 2024-06-04 08:47:07 +00:00
Kacper Magdziarz
8e3eeb9dd7 [ACS-5648] Add header 'X-Alfresco-Retry-Needed' indicating that recovery mode is on and client should retry later (#2670)
* [ACS-5648] Add header'X-Alfresco-Retry-Needed' indicating that recovery mode is on and client should retry later

* [ACS-5648] Bump ATS to 4.1.3-A1
2024-06-04 10:11:40 +02:00
alfresco-build
012d2f37c7 [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-03 18:42:01 +00:00
alfresco-build
f5f73162bd [maven-release-plugin][skip ci] prepare release 23.3.0.45 2024-06-03 18:41:58 +00:00
Piotr Żurek
e7a83f2641 ACS-8077 Bump Netty and Camel (#2678) 2024-06-03 19:56:14 +02:00
alfresco-build
2a300f9b7c [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-03 11:00:19 +00:00
alfresco-build
ac0ed124aa [maven-release-plugin][skip ci] prepare release 23.3.0.44 2024-06-03 11:00:17 +00:00
Tom Page
cee2da9700 Merge pull request #2661 from Alfresco/feature/PRODENG-276_implement_service_accounts
PRODENG-276: Implement service accounts
2024-06-03 11:24:12 +01:00
alfresco-build
2bc914b649 [maven-release-plugin][skip ci] prepare for next development iteration 2024-06-02 00:06:43 +00:00
alfresco-build
dcd381923e [maven-release-plugin][skip ci] prepare release 23.3.0.43 2024-06-02 00:06:41 +00:00
Alfresco CI User
bcf5d1b2c0 [force] Force release for 2024-06-02. 2024-06-02 00:03:31 +00:00
Jamal Kaabi-Mofrad
89dd6f7b35 PRODENG-276: Addressed minor comments from peer review. 2024-05-31 14:49:44 +01:00
Jamal Kaabi-Mofrad
c82e8d652a PRODENG-276: Resolved peer review comments. 2024-05-30 17:29:04 +01:00
Jamal Kaabi-Mofrad
a9a911e77f PRODENG-276: Resolved PMD issues. 2024-05-30 17:06:24 +01:00
Jamal Kaabi-Mofrad
e59bb3261c PRODENG-276: Fixed test failures. 2024-05-30 15:57:46 +01:00
alfresco-build
dbcb54369a [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-27 14:44:21 +00:00
alfresco-build
b50a022e48 [maven-release-plugin][skip ci] prepare release 23.3.0.42 2024-05-27 14:44:18 +00:00
Domenico Sibilio
799db5f212 ACS-7569 Test with Keycloak 24.0.3 (#2663) 2024-05-27 15:57:08 +02:00
alfresco-build
975976db18 [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-26 00:06:33 +00:00
alfresco-build
809fa28023 [maven-release-plugin][skip ci] prepare release 23.3.0.41 2024-05-26 00:06:31 +00:00
Alfresco CI User
d28359c168 [force] Force release for 2024-05-26. 2024-05-26 00:03:40 +00:00
Jamal Kaabi-Mofrad
d999558b33 PRODENG-276: Cleanup - Fixed inconsistent spacing issues. 2024-05-24 16:04:49 +01:00
Jamal Kaabi-Mofrad
897bfa8410 PRODENG-276: Implemented three distinct service account roles with varying access levels. 2024-05-24 15:54:10 +01:00
alfresco-build
a3b13ed8de [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-20 08:04:40 +00:00
alfresco-build
ea66b9e4f3 [maven-release-plugin][skip ci] prepare release 23.3.0.40 2024-05-20 08:04:38 +00:00
Kacper Magdziarz
0a5827e37c [ACS-7896] Bump AIS/ATS 5.1.2/4.1.2 (#2655) 2024-05-20 09:17:01 +02:00
alfresco-build
c01d1f8c3c [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-19 00:07:13 +00:00
alfresco-build
3895ce6584 [maven-release-plugin][skip ci] prepare release 23.3.0.39 2024-05-19 00:07:11 +00:00
Alfresco CI User
d01f9eb27b [force] Force release for 2024-05-19. 2024-05-19 00:03:26 +00:00
alfresco-build
325dfd285b [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-17 09:51:21 +00:00
alfresco-build
d907461972 [maven-release-plugin][skip ci] prepare release 23.3.0.38 2024-05-17 09:51:18 +00:00
SathishK-T
01a2587555 [MNT-24195] Added fix for ags capability issue (#2648)
* [MNT-24195] added fix for ags capability issue

* [MNT-24195] Build Issue Resolved

* [MNT-24195] Removed unused import

* [MNT-24195] Build issue changes

* [MNT-24195]  added fix for ags capability issue

* [MNT-24195] Added fix for ags capability issue

* [MNT-24195] Fix for Review Comment

* [MNT-24195] Fix for Review Comment

---------

Co-authored-by: Sathish Kumar <ST28@ford.com>
2024-05-17 14:41:46 +05:30
alfresco-build
8b45d19b00 [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-14 14:54:41 +00:00
alfresco-build
0b4b1dac44 [maven-release-plugin][skip ci] prepare release 23.3.0.37 2024-05-14 14:54:38 +00:00
Damian Ujma
f8becd3523 ACS-6309 Fix AGS Integration Tests (PostgreSQL) (#2643) 2024-05-14 16:19:01 +02:00
alfresco-build
781b56f06d [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-12 00:07:23 +00:00
alfresco-build
92656a68a9 [maven-release-plugin][skip ci] prepare release 23.3.0.36 2024-05-12 00:07:20 +00:00
Alfresco CI User
99838a73e3 [force] Force release for 2024-05-12. 2024-05-12 00:03:49 +00:00
alfresco-build
723156a86a [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-10 09:30:29 +00:00
alfresco-build
3f6692a63b [maven-release-plugin][skip ci] prepare release 23.3.0.35 2024-05-10 09:30:27 +00:00
kcichonczyk
32e72f204a [ACS-7895] Bump ATS (#2638) 2024-05-10 10:54:28 +02:00
alfresco-build
f5868e7f45 [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-09 12:34:32 +00:00
alfresco-build
fd015de2c8 [maven-release-plugin][skip ci] prepare release 23.3.0.34 2024-05-09 12:34:30 +00:00
Tom Page
ec2494f2b5 Merge pull request #2634 from Alfresco/dependabot/github_actions/actions/checkout-4
Bump actions/checkout from 3 to 4
2024-05-09 12:58:49 +01:00
alfresco-build
afc7e73352 [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-08 16:53:59 +00:00
alfresco-build
3519fd6a71 [maven-release-plugin][skip ci] prepare release 23.3.0.33 2024-05-08 16:53:57 +00:00
dependabot[bot]
5e43f3d4ab Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-08 16:14:50 +00:00
Tom Page
337d0b8f8f Merge pull request #2630 from Alfresco/feature/GHADependabot
Add GHA to Dependabot scanning.
2024-05-08 17:13:48 +01:00
Tom Page
3c7593265d Add GHA to Dependabot scanning. 2024-05-08 14:52:01 +01:00
alfresco-build
5dcecb7f19 [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-05 00:07:19 +00:00
alfresco-build
0617a441d3 [maven-release-plugin][skip ci] prepare release 23.3.0.32 2024-05-05 00:07:16 +00:00
Alfresco CI User
d9abdc23d5 [force] Force release for 2024-05-05. 2024-05-05 00:03:35 +00:00
alfresco-build
f132ec0a91 [maven-release-plugin][skip ci] prepare for next development iteration 2024-05-02 08:00:53 +00:00
alfresco-build
1797781ce8 [maven-release-plugin][skip ci] prepare release 23.3.0.31 2024-05-02 08:00:51 +00:00
Manish Kumar
88c1c849ed Merge pull request #2440 from fawhgb/rm-fileplan-caching-issue
Fixes the caching issue by returning a copy of the set instead of the Set
2024-05-02 12:53:50 +05:30
alfresco-build
c4ac7621c2 [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-30 10:08:30 +00:00
alfresco-build
bf7432deb1 [maven-release-plugin][skip ci] prepare release 23.3.0.30 2024-04-30 10:08:28 +00:00
dependabot[bot]
6f74667a5c Bump commons-codec:commons-codec from 1.16.0 to 1.17.0 (#2614)
Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.16.0 to 1.17.0.
- [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt)
- [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.16.0...rel/commons-codec-1.17.0)

---
updated-dependencies:
- dependency-name: commons-codec:commons-codec
  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>
2024-04-30 11:32:53 +02:00
alfresco-build
1e1508b74e [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-29 11:29:50 +00:00
alfresco-build
da8ffa08a0 [maven-release-plugin][skip ci] prepare release 23.3.0.29 2024-04-29 11:29:48 +00:00
dependabot[bot]
277dbd1054 Bump org.springframework:spring-web from 6.0.17 to 6.0.19 (#2612)
Bumps [org.springframework:spring-web](https://github.com/spring-projects/spring-framework) from 6.0.17 to 6.0.19.
- [Release notes](https://github.com/spring-projects/spring-framework/releases)
- [Commits](https://github.com/spring-projects/spring-framework/compare/v6.0.17...v6.0.19)

---
updated-dependencies:
- dependency-name: org.springframework:spring-web
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 12:43:14 +02:00
dependabot[bot]
43cfa0d872 Bump org.messaginghub:pooled-jms from 3.1.2 to 3.1.6 (#2611)
Bumps [org.messaginghub:pooled-jms](https://github.com/messaginghub/pooled-jms) from 3.1.2 to 3.1.6.
- [Commits](https://github.com/messaginghub/pooled-jms/compare/3.1.2...3.1.6)

---
updated-dependencies:
- dependency-name: org.messaginghub:pooled-jms
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-29 12:39:44 +02:00
alfresco-build
1325ec5718 [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-28 00:07:07 +00:00
alfresco-build
ecde2b5b60 [maven-release-plugin][skip ci] prepare release 23.3.0.28 2024-04-28 00:07:05 +00:00
Alfresco CI User
a9f75638c6 [force] Force release for 2024-04-28. 2024-04-28 00:04:18 +00:00
alfresco-build
a80b996f7e [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-21 00:06:44 +00:00
alfresco-build
05aa6b4cf6 [maven-release-plugin][skip ci] prepare release 23.3.0.27 2024-04-21 00:06:42 +00:00
Alfresco CI User
50b1d3a52e [force] Force release for 2024-04-21. 2024-04-21 00:03:37 +00:00
alfresco-build
38b763c635 [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-15 12:36:56 +00:00
alfresco-build
762b6ce607 [maven-release-plugin][skip ci] prepare release 23.3.0.26 2024-04-15 12:36:53 +00:00
Aleksandra Onych
0d89010ae6 [ACS-6776] add comment to json-path dependency (#2588) 2024-04-15 14:01:04 +02:00
Piotr Żurek
b744f267c1 ACS-7483 Bump ATS (#2589) 2024-04-15 13:59:59 +02:00
alfresco-build
e840726a7d [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-15 07:57:48 +00:00
alfresco-build
c53683df85 [maven-release-plugin][skip ci] prepare release 23.3.0.25 2024-04-15 07:57:45 +00:00
Alfresco CI User
d9e58483ff [force] Force release for 2024-04-14. 2024-04-14 00:07:14 +00:00
alfresco-build
9e81472d06 [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-12 13:29:27 +00:00
alfresco-build
3e9cdc6b77 [maven-release-plugin][skip ci] prepare release 23.3.0.24 2024-04-12 13:29:25 +00:00
Domenico Sibilio
e8ac8c2602 ACS-7481 Bump IE/SS to 2.0.10 (#2585) 2024-04-12 14:50:41 +02:00
alfresco-build
eea58f4ba3 [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-10 11:37:55 +00:00
alfresco-build
a95fa4a83d [maven-release-plugin][skip ci] prepare release 23.3.0.23 2024-04-10 11:37:52 +00:00
Aleksandra Onych
0b74d283e2 [ACS-6935] Update tika version to 2.9.2 (#2578) 2024-04-10 13:03:10 +02:00
alfresco-build
052e21e62d [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-10 08:52:46 +00:00
alfresco-build
26f49e80e9 [maven-release-plugin][skip ci] prepare release 23.3.0.22 2024-04-10 08:52:43 +00:00
Eva Vasques
c31158a113 MNT-24321 Transfer Service Exception Handling (#2573)
* Mark method deserialize in ExceptionJsonSerializer as deprecated
* Remove usage of jsonErrorSerializer
2024-04-10 09:15:25 +01:00
alfresco-build
2b4fc52203 [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-07 00:06:32 +00:00
alfresco-build
6222e1dfde [maven-release-plugin][skip ci] prepare release 23.3.0.21 2024-04-07 00:06:30 +00:00
Alfresco CI User
077c48dea9 [force] Force release for 2024-04-07. 2024-04-07 00:03:33 +00:00
alfresco-build
1a0b8d8dee [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-05 15:39:32 +00:00
alfresco-build
66d007e703 [maven-release-plugin][skip ci] prepare release 23.3.0.20 2024-04-05 15:39:29 +00:00
Domenico Sibilio
81a4c5bac0 ACS-6961 Bump IE/SS to 2.0.10-A1 (#2571) 2024-04-05 14:09:59 +02:00
alfresco-build
018157c808 [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-04 13:19:11 +00:00
alfresco-build
8db97184f2 [maven-release-plugin][skip ci] prepare release 23.3.0.19 2024-04-04 13:19:09 +00:00
Piotr Żurek
84948e051a ACS-7467 Fix grep escaping (#2567) 2024-04-04 14:43:31 +02:00
alfresco-build
8c20a3271e [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-04 10:33:26 +00:00
alfresco-build
48c7abcfbe [maven-release-plugin][skip ci] prepare release 23.3.0.18 2024-04-04 10:33:24 +00:00
Damian Ujma
53d77f8d71 ACS-6917 Implement the Legal Holds v1 API (#2566)
---------

Co-authored-by: Tom Page <tpage-alfresco@users.noreply.github.com>
Co-authored-by: Domenico Sibilio <domenicosibilio@gmail.com>
2024-04-04 11:46:56 +02:00
alfresco-build
e8e747347a [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-03 13:45:11 +00:00
alfresco-build
fee244cb08 [maven-release-plugin][skip ci] prepare release 23.3.0.17 2024-04-03 13:45:09 +00:00
Piotr Żurek
2bec2bd1c4 ACS-7467 Migrate to Docker Compose V2 (#2560) 2024-04-03 15:08:10 +02:00
Piotr Żurek
1cd8098f52 ACS-7313 Bump ATS in ACS 23.3 (#2559) 2024-04-03 14:49:38 +02:00
alfresco-build
30afcaa033 [maven-release-plugin][skip ci] prepare for next development iteration 2024-04-03 08:49:21 +00:00
alfresco-build
bdf1a57630 [maven-release-plugin][skip ci] prepare release 23.3.0.16 2024-04-03 08:49:19 +00:00
Wojtek Świętoń
2723817832 ACS-6309 Integration with Report Portal (#2445) 2024-04-03 09:46:01 +02:00
alfresco-build
22acb2abe7 [maven-release-plugin][skip ci] prepare for next development iteration 2024-03-31 00:07:05 +00:00
alfresco-build
3c616152a1 [maven-release-plugin][skip ci] prepare release 23.3.0.15 2024-03-31 00:07:03 +00:00
Alfresco CI User
8cfdc613cb [force] Force release for 2024-03-31. 2024-03-31 00:04:13 +00:00
alfresco-build
f1919934b2 [maven-release-plugin][skip ci] prepare for next development iteration 2024-03-29 09:20:56 +00:00
alfresco-build
e9da60dac3 [maven-release-plugin][skip ci] prepare release 23.3.0.14 2024-03-29 09:20:53 +00:00
kcichonczyk
0597b0997f [ACS-7320] ATS/AIS version bump to java11 compatible 2024-03-29 09:45:52 +01:00
alfresco-build
6dbe30e8f7 [maven-release-plugin][skip ci] prepare for next development iteration 2024-03-27 14:27:38 +00:00
alfresco-build
d978b1cd68 [maven-release-plugin][skip ci] prepare release 23.3.0.13 2024-03-27 14:27:35 +00:00
Piotr Żurek
dce356fe74 MNT-23210 Fix audit min-max query (#2545) 2024-03-27 14:49:35 +01:00
alfresco-build
f965165894 [maven-release-plugin][skip ci] prepare for next development iteration 2024-03-24 00:06:39 +00:00
alfresco-build
2ac44c24a8 [maven-release-plugin][skip ci] prepare release 23.3.0.12 2024-03-24 00:06:37 +00:00
Alfresco CI User
a0dc5a0d70 [force] Force release for 2024-03-24. 2024-03-24 00:04:10 +00:00
alfresco-build
af94063bbb [maven-release-plugin][skip ci] prepare for next development iteration 2024-03-18 16:00:10 +00:00
alfresco-build
87b91b6cae [maven-release-plugin][skip ci] prepare release 23.3.0.11 2024-03-18 16:00:08 +00:00
mohit-singh4
6bdcaa9b10 [APPS-2576] fix for Security Web Vulnerability (#2516) 2024-03-18 20:54:04 +05:30
Maciej Pichura
86070d881c ACS-6884: Bump api-explorer version to 23.2.0 (GA) (#2480)
* ACS-6884: Bump api-explorer version to 23.2.0 (GA)

* Bump org.springframework.security:spring-security-bom (#2453)

Bumps [org.springframework.security:spring-security-bom](https://github.com/spring-projects/spring-security) from 6.1.4 to 6.2.2.
- [Release notes](https://github.com/spring-projects/spring-security/releases)
- [Changelog](https://github.com/spring-projects/spring-security/blob/main/RELEASE.adoc)
- [Commits](https://github.com/spring-projects/spring-security/compare/6.1.4...6.2.2)

---
updated-dependencies:
- dependency-name: org.springframework.security:spring-security-bom
  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>

* ACS-6931 Temporarily turn off SAST Scan (#2489)

ACS-6931 Temporarily turn off SAST Scan

* [maven-release-plugin][skip ci] prepare release 23.3.0.7

* [maven-release-plugin][skip ci] prepare for next development iteration

* [force] Force release for 2024-03-10.

* [maven-release-plugin][skip ci] prepare release 23.3.0.8

* [maven-release-plugin][skip ci] prepare for next development iteration

* MNT-24250: bump xalan version (#2497)

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* bump xalan

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: alfresco.3

* MNT-24250: alfresco.3

* MNT-24250: alfresco.3

* MNT-24250: alfresco.3

* MNT-24250: alfresco.3

* MNT-24250: 2.7.3 official

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco

* MNT-24250: 2.7.3-alfresco

* MNT-24250: 2.7.3-alfresco

* MNT-24250: 2.7.3-alfresco

* [maven-release-plugin][skip ci] prepare release 23.3.0.9

* [maven-release-plugin][skip ci] prepare for next development iteration

* [force] Force release for 2024-03-17.

* [maven-release-plugin][skip ci] prepare release 23.3.0.10

* [maven-release-plugin][skip ci] prepare for next development iteration

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: mikolajbrzezinski <86791239+mikolajbrzezinski@users.noreply.github.com>
Co-authored-by: alfresco-build <8039454+alfresco-build@users.noreply.github.com>
Co-authored-by: Alfresco CI User <build@alfresco.com>
Co-authored-by: Paweł Rainer <62990104+Pawel-608@users.noreply.github.com>
2024-03-18 11:54:56 +01:00
alfresco-build
a82199967c [maven-release-plugin][skip ci] prepare for next development iteration 2024-03-17 00:06:51 +00:00
alfresco-build
f09266c081 [maven-release-plugin][skip ci] prepare release 23.3.0.10 2024-03-17 00:06:49 +00:00
Alfresco CI User
563f65825f [force] Force release for 2024-03-17. 2024-03-17 00:04:08 +00:00
alfresco-build
8bedeedfd5 [maven-release-plugin][skip ci] prepare for next development iteration 2024-03-14 10:11:22 +00:00
alfresco-build
a73cf6a71d [maven-release-plugin][skip ci] prepare release 23.3.0.9 2024-03-14 10:11:19 +00:00
Paweł Rainer
1bdd6c022c MNT-24250: bump xalan version (#2497)
* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* bump xalan

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: bump xalan version

* MNT-24250: alfresco.3

* MNT-24250: alfresco.3

* MNT-24250: alfresco.3

* MNT-24250: alfresco.3

* MNT-24250: alfresco.3

* MNT-24250: 2.7.3 official

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco.3

* MNT-24250: 2.7.3-alfresco

* MNT-24250: 2.7.3-alfresco

* MNT-24250: 2.7.3-alfresco

* MNT-24250: 2.7.3-alfresco
2024-03-14 10:34:09 +01:00
alfresco-build
1b553dbcaf [maven-release-plugin][skip ci] prepare for next development iteration 2024-03-10 00:06:19 +00:00
alfresco-build
5a3b4e1a0d [maven-release-plugin][skip ci] prepare release 23.3.0.8 2024-03-10 00:06:17 +00:00
Alfresco CI User
1a0156b1e5 [force] Force release for 2024-03-10. 2024-03-10 00:03:35 +00:00
alfresco-build
6ac9248262 [maven-release-plugin][skip ci] prepare for next development iteration 2024-03-06 12:46:46 +00:00
alfresco-build
70290c8f23 [maven-release-plugin][skip ci] prepare release 23.3.0.7 2024-03-06 12:46:43 +00:00
mikolajbrzezinski
7d135b9356 ACS-6931 Temporarily turn off SAST Scan (#2489)
ACS-6931 Temporarily turn off SAST Scan
2024-03-06 13:11:31 +01:00
dependabot[bot]
df4629b801 Bump org.springframework.security:spring-security-bom (#2453)
Bumps [org.springframework.security:spring-security-bom](https://github.com/spring-projects/spring-security) from 6.1.4 to 6.2.2.
- [Release notes](https://github.com/spring-projects/spring-security/releases)
- [Changelog](https://github.com/spring-projects/spring-security/blob/main/RELEASE.adoc)
- [Commits](https://github.com/spring-projects/spring-security/compare/6.1.4...6.2.2)

---
updated-dependencies:
- dependency-name: org.springframework.security:spring-security-bom
  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>
2024-03-05 12:02:56 +01:00
alfresco-build
df6f656b95 [maven-release-plugin][skip ci] prepare for next development iteration 2024-03-03 00:05:44 +00:00
alfresco-build
f27718c43b [maven-release-plugin][skip ci] prepare release 23.3.0.6 2024-03-03 00:05:42 +00:00
Alfresco CI User
cbf0aaaaa4 [force] Force release for 2024-03-03. 2024-03-03 00:03:20 +00:00
alfresco-build
2da78a94ad [maven-release-plugin][skip ci] prepare for next development iteration 2024-02-26 08:21:03 +00:00
alfresco-build
3325e08d57 [maven-release-plugin][skip ci] prepare release 23.3.0.5 2024-02-26 08:21:01 +00:00
rrajoria
985205e78e Update google drive and aos GA Version 2024-02-26 13:16:08 +05:30
alfresco-build
5fd5e75bd2 [maven-release-plugin][skip ci] prepare for next development iteration 2024-02-25 00:06:12 +00:00
alfresco-build
279bc15aac [maven-release-plugin][skip ci] prepare release 23.3.0.4 2024-02-25 00:06:10 +00:00
Alfresco CI User
a3283b4521 [force] Force release for 2024-02-25. 2024-02-25 00:03:36 +00:00
alfresco-build
e09c9118b2 [maven-release-plugin][skip ci] prepare for next development iteration 2024-02-23 07:45:42 +00:00
alfresco-build
330256438b [maven-release-plugin][skip ci] prepare release 23.3.0.3 2024-02-23 07:45:40 +00:00
Kacper Magdziarz
2214f16e6e [ACS-6773] Propagate ATS-4.1.0 (#2469) 2024-02-23 08:10:12 +01:00
alfresco-build
2237a45e76 [maven-release-plugin][skip ci] prepare for next development iteration 2024-02-21 11:20:16 +00:00
alfresco-build
f71a003904 [maven-release-plugin][skip ci] prepare release 23.3.0.2 2024-02-21 11:20:13 +00:00
dependabot[bot]
10d55824f8 Bump org.apache.commons:commons-compress from 1.25.0 to 1.26.0 (#2454)
Bumps org.apache.commons:commons-compress from 1.25.0 to 1.26.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-compress
  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>
2024-02-21 11:36:18 +01:00
alfresco-build
69f8bda762 [maven-release-plugin][skip ci] prepare for next development iteration 2024-02-20 13:01:23 +00:00
alfresco-build
d8de1ba353 [maven-release-plugin][skip ci] prepare release 23.3.0.1 2024-02-20 13:01:21 +00:00
Damian Ujma
d4d8718f16 ACS-6601 Bump AOS to 3.0.0-A1 (#2459) 2024-02-20 13:17:35 +01:00
Krystian Dabrowski
859492ae1e ACS-6113: Fix secondary parents to never be set to null (#2460) 2024-02-20 12:47:28 +01:00
mpichura
6c08a60ce5 Updating master branch to 23.3.0 after 23.2.0 ACS release [skip ci] 2024-02-19 16:34:39 +01:00
Simon Wagner
440e31fcdb Fixes the caching issue by returning a copy of the set instead of the set inside the cache. 2024-02-08 09:17:10 +01:00
242 changed files with 13938 additions and 1263 deletions

View File

@@ -52,3 +52,7 @@ updates:
interval: "daily"
time: "22:00"
timezone: Africa/Abidjan
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"

View File

@@ -29,6 +29,9 @@ env:
AUTH0_CLIENT_ID: ${{ secrets.AUTH0_OIDC_ADMIN_CLIENT_ID }}
AUTH0_CLIENT_SECRET: ${{ secrets.AUTH0_OIDC_CLIENT_SECRET }}
AUTH0_ADMIN_PASSWORD: ${{ secrets.AUTH0_OIDC_ADMIN_PASSWORD }}
# Report Portal settings
RP_LAUNCH_PREFIX: "${{ github.workflow }} - ${{ github.job }}"
RP_PROJECT: alfresco-backend
jobs:
prepare:
@@ -38,7 +41,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -58,7 +61,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -81,7 +84,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -97,7 +100,7 @@ jobs:
bash ./scripts/ci/init.sh
bash ./scripts/ci/build.sh
- name: "Run SAST Scan"
uses: veracode/Veracode-pipeline-scan-action@v1.0.10
uses: veracode/Veracode-pipeline-scan-action@v1.0.16
with:
vid: ${{ secrets.VERACODE_API_ID }}
vkey: ${{ secrets.VERACODE_API_KEY }}
@@ -135,29 +138,87 @@ jobs:
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
- uses: Alfresco/ya-pmd-scan@v3.0.0
- uses: Alfresco/ya-pmd-scan@v4.0.0
with:
classpath-build-command: "mvn test-compile -ntp -Pags -pl \"-:alfresco-community-repo-docker\""
all_unit_tests_suite:
name: "Core, Data-Model, Repository - AllUnitTestsSuite - Build and test"
name: ${{ matrix.testName }} - AllUnitTestsSuite - Build and test
runs-on: ubuntu-latest
needs: [prepare]
if: >
!contains(github.event.head_commit.message, '[skip repo]') &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
strategy:
fail-fast: false
matrix:
include:
- testName: Core
testModule: core
testAttributes: "-Dtest=AllCoreUnitTestSuite"
- testName: Data-Model
testModule: data-model
testAttributes: "-Dtest=AllDataModelUnitTestSuite"
- testName: Repository
testModule: repository
testAttributes: "-Dtest=AllUnitTestsSuite"
- testName: Mmt
testModule: mmt
testAttributes: "-Dtest=AllMmtUnitTestSuite"
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
- name: "Init"
run: bash ./scripts/ci/init.sh
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testModule }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
mvn -B test -pl core,data-model -am -DfailIfNoTests=false
mvn -B test -pl "repository,mmt" -am "-Dtest=AllUnitTestsSuite,AllMmtUnitTestSuite" -DfailIfNoTests=false
eval "args=($RP_OPTS)"
mvn -B test -pl ${{ matrix.testModule }} -am ${{ matrix.testAttributes }} -DfailIfNoTests=false "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -186,7 +247,7 @@ jobs:
env:
REQUIRES_INSTALLED_ARTIFACTS: true
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -199,8 +260,52 @@ jobs:
run: echo "TRANSFORMERS_TAG=$(mvn help:evaluate -Dexpression=dependency.alfresco-transform-core.version -q -DforceStdout)" >> $GITHUB_ENV
- name: "Set up the environment"
run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testSuite }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
run: mvn -B test -pl remote-api -Dtest=${{ matrix.testSuite }} -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl remote-api -Dtest=${{ matrix.testSuite }} -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -220,7 +325,7 @@ jobs:
matrix:
version: ['10.2.18', '10.4', '10.5']
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -230,8 +335,52 @@ jobs:
run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mariadb up -d
env:
MARIADB_VERSION: ${{ matrix.version }}
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.version }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
run: mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.name=alfresco -Ddb.url=jdbc:mariadb://localhost:3307/alfresco?useUnicode=yes\&characterEncoding=UTF-8 -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.driver=org.mariadb.jdbc.Driver
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.name=alfresco -Ddb.url=jdbc:mariadb://localhost:3307/alfresco?useUnicode=yes\&characterEncoding=UTF-8 -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.driver=org.mariadb.jdbc.Driver "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -247,7 +396,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -257,8 +406,52 @@ jobs:
run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mariadb up -d
env:
MARIADB_VERSION: 10.6
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
run: mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.name=alfresco -Ddb.url=jdbc:mariadb://localhost:3307/alfresco?useUnicode=yes\&characterEncoding=UTF-8 -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.driver=org.mariadb.jdbc.Driver
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.name=alfresco -Ddb.url=jdbc:mariadb://localhost:3307/alfresco?useUnicode=yes\&characterEncoding=UTF-8 -Ddb.username=alfresco -Ddb.password=alfresco -Ddb.driver=org.mariadb.jdbc.Driver "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -274,7 +467,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -284,8 +477,52 @@ jobs:
run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mysql up -d
env:
MYSQL_VERSION: 8
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
run: mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=com.mysql.jdbc.Driver -Ddb.name=alfresco -Ddb.url=jdbc:mysql://localhost:3307/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=com.mysql.jdbc.Driver -Ddb.name=alfresco -Ddb.url=jdbc:mysql://localhost:3307/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -300,7 +537,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -310,8 +547,52 @@ jobs:
run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
env:
POSTGRES_VERSION: 13.12
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
run: mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -326,7 +607,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -336,8 +617,52 @@ jobs:
run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
env:
POSTGRES_VERSION: 14.9
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
run: mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -352,7 +677,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -362,8 +687,52 @@ jobs:
run: docker compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
env:
POSTGRES_VERSION: 15.4
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
run: mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=AllDBTestsTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -376,7 +745,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -384,8 +753,52 @@ jobs:
run: bash ./scripts/ci/init.sh
- name: "Run ActiveMQ"
run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile activemq up -d
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.13.1
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
run: mvn -B test -pl repository -am -Dtest=CamelRoutesTest,CamelComponentsTest -DfailIfNoTests=false
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=MessagingUnitTestSuite -DfailIfNoTests=false "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.13.1
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -432,7 +845,7 @@ jobs:
disabledHostnameVerification: false
mvn-options: '-Dencryption.ssl.keystore.location=${CI_WORKSPACE}/keystores/alfresco/alfresco.keystore -Dencryption.ssl.truststore.location=${CI_WORKSPACE}/keystores/alfresco/alfresco.truststore'
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -455,8 +868,52 @@ jobs:
fi
- name: "Set up the environment"
run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.testSuite }} ${{ matrix.idp }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
run: mvn -B test -pl repository -am -Dtest=${{ matrix.testSuite }} -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco ${{ matrix.mvn-options }}
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl repository -am -Dtest=${{ matrix.testSuite }} -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco ${{ matrix.mvn-options }} "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -501,7 +958,7 @@ jobs:
env:
REQUIRES_LOCAL_IMAGES: true
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -517,16 +974,59 @@ jobs:
- name: "Build TAS integration tests"
if: ${{ matrix.test-name }} == 'Integration TAS tests'
run: mvn install -pl :alfresco-community-repo-integration-test -am -DskipTests -Pall-tas-tests
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} - ${{ matrix.test-name }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
id: tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: mvn -B verify -f packaging/tests/${{ matrix.pom-dir }}/pom.xml -Pall-tas-tests,${{ matrix.test-profile }} -Denvironment=default -DrunBugs=false
run: |
eval "args=($RP_OPTS)"
mvn -B verify -f packaging/tests/${{ matrix.pom-dir }}/pom.xml -Pall-tas-tests,${{ matrix.test-profile }} -Denvironment=default -DrunBugs=false "${args[@]}"
continue-on-error: true
- name: "Print output after success"
if: ${{ always() && steps.tests.outcome == 'success' }}
run: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/${{ matrix.pom-dir }}"
- name: "Print output after failure"
if: ${{ always() && steps.tests.outcome == 'failure' }}
run: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/${{ matrix.pom-dir }}"
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.tests.outcome != 'success'
run: |
echo "::error title=tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -539,7 +1039,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -547,8 +1047,52 @@ jobs:
run: bash ./scripts/ci/init.sh
- name: "Run Postgres 15.4 database"
run: docker compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile postgres up -d
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Run tests"
run: mvn -B test -pl :alfresco-share-services -am -Dtest=ShareServicesTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
id: run-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl :alfresco-share-services -am -Dtest=ShareServicesTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -569,7 +1113,7 @@ jobs:
env:
REQUIRES_INSTALLED_ARTIFACTS: true
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -578,9 +1122,23 @@ jobs:
run: |
bash ./scripts/ci/init.sh
bash ./scripts/ci/build.sh
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} 0${{ matrix.part }} - (PostgreSQL) ${{ matrix.test-name }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Verify"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: mvn --file amps/ags/pom.xml -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-postgres -PagsAllTestSuitePt${{ matrix.part }} ${{ env.LOG_WARN }}
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn --file amps/ags/pom.xml -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-postgres -PagsAllTestSuitePt${{ matrix.part }} ${{ env.LOG_WARN }} "${args[@]}"
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -601,7 +1159,7 @@ jobs:
env:
REQUIRES_INSTALLED_ARTIFACTS: true
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -610,9 +1168,23 @@ jobs:
run: |
bash ./scripts/ci/init.sh
bash ./scripts/ci/build.sh
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }} 0${{ matrix.part }} - (MySQL) ${{ matrix.test-name }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Verify"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: mvn --file amps/ags/pom.xml -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-mysql -PagsAllTestSuitePt${{ matrix.part }} ${{ env.LOG_WARN }}
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn --file amps/ags/pom.xml -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-mysql -PagsAllTestSuitePt${{ matrix.part }} ${{ env.LOG_WARN }} "${args[@]}"
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
@@ -629,7 +1201,7 @@ jobs:
env:
REQUIRES_LOCAL_IMAGES: true
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2
@@ -644,9 +1216,53 @@ jobs:
${{ env.TAS_SCRIPTS }}/start-compose.sh ./amps/ags/rm-community/rm-community-repo/docker-compose.yml
${{ env.TAS_SCRIPTS }}/wait-for-alfresco-start.sh "http://localhost:8080/alfresco"
mvn -B install -pl :alfresco-governance-services-automation-community-rest-api -am -Pags -Pall-tas-tests -DskipTests
- name: "Prepare Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-prepare@v5.1.0
id: rp-prepare
with:
rp-launch-prefix: ${{ env.RP_LAUNCH_PREFIX }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
rp-project: ${{ env.RP_PROJECT }}
rp-use-static-launch-name: true
continue-on-error: true
- name: "Add GitHub Step Summary"
if: github.ref_name == 'master'
env:
RP_ENABLED: ${{ steps.rp-prepare.outputs.enabled }}
RP_KEY: ${{ steps.rp-prepare.outputs.key }}
RP_URL: ${{ steps.rp-prepare.outputs.url }}
run: bash scripts/ci/add_step_summary.sh
continue-on-error: true
- name: "Test"
id: run-tests
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: mvn -B test -pl :alfresco-governance-services-automation-community-rest-api -Dskip.automationtests=false -Pags -Pall-tas-tests
env:
RP_OPTS: ${{ github.ref_name == 'master' && steps.rp-prepare.outputs.mvn-opts || '' }}
run: |
eval "args=($RP_OPTS)"
mvn -B test -pl :alfresco-governance-services-automation-community-rest-api -Dskip.automationtests=false -Pags -Pall-tas-tests "${args[@]}"
continue-on-error: true
- name: "Update GitHub Step Summary"
if: github.ref_name == 'master'
run: |
echo "#### ⏱ After Tests: $(date -u +'%Y-%m-%d %H:%M:%S%:z')" >> $GITHUB_STEP_SUMMARY
continue-on-error: true
- name: "Summarize Report Portal"
if: github.ref_name == 'master'
uses: Alfresco/alfresco-build-tools/.github/actions/reportportal-summarize@v5.1.0
id: rp-summarize
with:
tests-outcome: ${{ steps.run-tests.outcome }}
rp-launch-key: ${{ steps.rp-prepare.outputs.key }}
rp-project: ${{ env.RP_PROJECT }}
rp-token: ${{ secrets.REPORT_PORTAL_TOKEN }}
continue-on-error: true
- name: "Exit on failure"
if: steps.run-tests.outcome != 'success'
run: |
echo "::error title=run-tests::Tests failed: re-throwing on error."
exit 1
- name: "Configure AWS credentials"
if: ${{ always() }}
uses: aws-actions/configure-aws-credentials@v1
@@ -675,7 +1291,7 @@ jobs:
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v1.35.2
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.35.2

View File

@@ -31,7 +31,7 @@ jobs:
!contains(github.event.head_commit.message, '[no release]') &&
github.event_name != 'pull_request'
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2
@@ -60,7 +60,7 @@ jobs:
!contains(github.event.head_commit.message, '[no downstream]') &&
github.event_name != 'pull_request'
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.35.2

View File

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

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
<version>23.2.2.2</version>
<version>23.3.0.87-SNAPSHOT</version>
</parent>
<build>
@@ -74,6 +74,22 @@
<artifactId>alfresco-testng</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.epam.reportportal</groupId>
<artifactId>agent-java-testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>${dependency.awaitility.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
@@ -82,7 +98,7 @@
<dependency>
<groupId>com.github.docker-java</groupId>
<artifactId>docker-java</artifactId>
<version>3.3.2</version>
<version>3.3.6</version>
<exclusions>
<exclusion>
<groupId>org.bouncycastle</groupId>

View File

@@ -39,6 +39,7 @@ import org.alfresco.rest.rm.community.requests.gscore.GSCoreAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.ActionsExecutionAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.FilesAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.HoldsAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RMUserAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordCategoryAPI;
@@ -48,6 +49,7 @@ import org.alfresco.rest.rm.community.requests.gscore.api.TransferAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.TransferContainerAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledContainerAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledRecordFolderAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RetentionScheduleAPI;
import org.alfresco.utility.data.DataUserAIS;
import org.alfresco.utility.model.RepoTestModel;
import org.alfresco.utility.model.UserModel;
@@ -243,4 +245,24 @@ public class RestAPIFactory
{
return getGSCoreAPI(null).usingActionsExecutionsAPI();
}
public HoldsAPI getHoldsAPI()
{
return getGSCoreAPI(null).usingHoldsAPI();
}
public HoldsAPI getHoldsAPI(UserModel userModel)
{
return getGSCoreAPI(userModel).usingHoldsAPI();
}
public RetentionScheduleAPI getRetentionScheduleAPI()
{
return getGSCoreAPI(null).usingRetentionScheduleAPI();
}
public RetentionScheduleAPI getRetentionScheduleAPI(UserModel userModel)
{
return getGSCoreAPI(userModel).usingRetentionScheduleAPI();
}
}

View File

@@ -61,7 +61,6 @@ public class FilePlanComponentFields
public static final String PROPERTIES_RECORD_SEARCH_DISPOSITION_EVENTS = "rma:recordSearchDispositionEvents";
public static final String PROPERTIES_DECLASSIFICATION_REVIEW_COMPLETED_BY = "rma:declassificationReviewCompletedBy";
public static final String PROPERTIES_DECLASSIFICATION_REVIEW_COMPLETED_AT = "rma:declassificationReviewCompletedAt";
/** File plan properties */
public static final String PROPERTIES_COMPONENT_ID = "st:componentId";

View File

@@ -0,0 +1,41 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BulkBodyCancel
{
private String reason;
}

View File

@@ -0,0 +1,83 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.alfresco.utility.model.TestModel;
/**
* POJO for hold
*
* @author Damian Ujma
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Hold extends TestModel
{
@JsonProperty(required = true)
private String id;
@JsonProperty(required = true)
private String name;
@JsonProperty(required = true)
private String description;
@JsonProperty(required = true)
private String reason;
@Override
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
Hold hold = (Hold) o;
return Objects.equals(id, hold.id) && Objects.equals(name, hold.name)
&& Objects.equals(description, hold.description) && Objects.equals(reason, hold.reason);
}
@Override
public int hashCode()
{
return Objects.hash(id, name, description, reason);
}
}

View File

@@ -0,0 +1,59 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.alfresco.rest.search.RestRequestQueryModel;
import org.alfresco.utility.model.TestModel;
/**
* POJO for hold bulk request
*
* @author Damian Ujma
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HoldBulkOperation extends TestModel
{
public enum HoldBulkOperationType
{
ADD
}
@JsonProperty(required = true)
private RestRequestQueryModel query;
@JsonProperty(required = true)
private HoldBulkOperationType op;
}

View File

@@ -0,0 +1,50 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* POJO for hold bulk request entry
*
* @author Damian Ujma
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HoldBulkOperationEntry
{
private String bulkStatusId;
private long totalItems;
}

View File

@@ -0,0 +1,67 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.alfresco.utility.model.TestModel;
/**
* POJO for hold bulk request
*
* @author Damian Ujma
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HoldBulkStatus extends TestModel
{
private String bulkStatusId;
private String startTime;
private String endTime;
private long processedItems;
private long errorsCount;
private long totalItems;
private String lastError;
private String status;
private boolean isCancelled;
private String cancellationReason;
private HoldBulkOperation holdBulkOperation;
}

View File

@@ -0,0 +1,38 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import org.alfresco.rest.core.RestModels;
/**
* Handle collection of {@link HoldBulkStatusEntry}
*
* @author Damian Ujma
*/
public class HoldBulkStatusCollection extends RestModels<HoldBulkStatusEntry, HoldBulkStatusCollection>
{
}

View File

@@ -0,0 +1,46 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.alfresco.rest.core.RestModels;
@Builder
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class HoldBulkStatusEntry extends RestModels<HoldBulkStatus, HoldBulkStatusEntry>
{
private HoldBulkStatus entry;
}

View File

@@ -0,0 +1,52 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.alfresco.utility.model.TestModel;
/**
* POJO for hold child
*
* @author Damian Ujma
*/
@Builder
@EqualsAndHashCode(callSuper = true)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HoldChild extends TestModel
{
@JsonProperty(required = true)
private String id;
}

View File

@@ -0,0 +1,38 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import org.alfresco.rest.core.RestModels;
/**
* Handle collection of {@link HoldChildEntry}
*
* @author Damian Ujma
*/
public class HoldChildCollection extends RestModels<HoldChildEntry, HoldChildCollection>
{
}

View File

@@ -0,0 +1,52 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.alfresco.rest.core.RestModels;
/**
* POJO for hold child entry
*
* @author Damian Ujma
*/
@Builder
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class HoldChildEntry extends RestModels<Hold, HoldChildEntry>
{
@JsonProperty
private HoldChild entry;
}

View File

@@ -0,0 +1,38 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import org.alfresco.rest.core.RestModels;
/**
* Handle collection of {@link HoldEntry}
*
* @author Damian Ujma
*/
public class HoldCollection extends RestModels<HoldEntry, HoldCollection>
{
}

View File

@@ -0,0 +1,52 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.alfresco.utility.model.TestModel;
/**
* POJO for hold deletion reason
*
* @author Damian Ujma
*/
@Builder
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class HoldDeletionReason extends TestModel
{
@JsonProperty
private String reason;
}

View File

@@ -0,0 +1,52 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.alfresco.rest.core.RestModels;
/**
* POJO for hold child entry
*
* @author Damian Ujma
*/
@Builder
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
public class HoldDeletionReasonEntry extends RestModels<HoldDeletionReason, HoldDeletionReasonEntry>
{
@JsonProperty
private HoldDeletionReason entry;
}

View File

@@ -26,31 +26,27 @@
*/
package org.alfresco.rest.rm.community.model.hold;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.alfresco.utility.model.TestModel;
import org.alfresco.rest.core.RestModels;
/**
* POJO for hold entry
*
* @author Rodica Sutu
* @since 3.2
* @author Damian Ujma
*/
@Builder
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties (ignoreUnknown = true)
public class HoldEntry extends TestModel
public class HoldEntry extends RestModels<Hold, HoldEntry>
{
@JsonProperty (required = true)
private String name;
@JsonProperty (required = true)
private String nodeRef;
@JsonProperty
private Hold entry;
}

View File

@@ -0,0 +1,56 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.hold.v0;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.alfresco.utility.model.TestModel;
/**
* POJO for hold entry
*
* @author Rodica Sutu
* @since 3.2
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties (ignoreUnknown = true)
public class HoldEntry extends TestModel
{
@JsonProperty (required = true)
private String name;
@JsonProperty (required = true)
private String nodeRef;
}

View File

@@ -0,0 +1,58 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.retentionschedule;
import lombok.EqualsAndHashCode;
import org.alfresco.utility.model.TestModel;
import lombok.Data;
import java.util.List;
/**
* retention schedule
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class RetentionSchedule extends TestModel
{
private String id ;
private String parentId;
private String authority;
private String instructions;
private boolean isRecordLevel;
private boolean isUnpublishedUpdates;
private List<RetentionScheduleActionDefinition> actions;
public boolean getIsRecordLevel()
{
return isRecordLevel;
}
public void setIsRecordLevel(boolean recordLevel) {
isRecordLevel = recordLevel;
}
}

View File

@@ -0,0 +1,50 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.retentionschedule;
import java.util.List;
import lombok.Data;
/**
* retention schedule action definition
*/
@Data
public class RetentionScheduleActionDefinition
{
private String id;
private String name;
private int periodAmount;
private String period;
private String periodProperty;
private boolean combineRetentionStepConditions;
private List<String> events;
private boolean eligibleOnFirstCompleteEvent;
private String description;
private boolean retainRecordMetadataAfterDestruction;
private String location;
private int index;
}

View File

@@ -0,0 +1,32 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.retentionschedule;
import org.alfresco.rest.core.RestModels;
public class RetentionScheduleCollection extends RestModels<RetentionScheduleEntry, RetentionScheduleCollection>
{
}

View File

@@ -0,0 +1,37 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.retentionschedule;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.alfresco.rest.core.RestModels;
@Data
public class RetentionScheduleEntry extends RestModels<RetentionSchedule, RetentionScheduleEntry>
{
@JsonProperty
private RetentionSchedule entry;
}

View File

@@ -0,0 +1,33 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.retentionschedule;
import org.alfresco.rest.core.RestModels;
public class RetentionScheduleStepCollection extends RestModels<RetentionScheduleStepEntry, RetentionScheduleStepCollection>
{
}

View File

@@ -0,0 +1,38 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.model.retentionschedule;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import org.alfresco.rest.core.RestModels;
@Data
public class RetentionScheduleStepEntry extends RestModels<RetentionScheduleActionDefinition, RetentionScheduleStepEntry>
{
@JsonProperty
private RetentionScheduleActionDefinition entry;
}

View File

@@ -37,6 +37,7 @@ import org.alfresco.rest.rm.community.requests.gscore.api.ActionsExecutionAPI;
import org.alfresco.rest.rm.community.requests.RMModelRequest;
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.FilesAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.HoldsAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RMSiteAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RMUserAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordCategoryAPI;
@@ -46,6 +47,7 @@ import org.alfresco.rest.rm.community.requests.gscore.api.TransferAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.TransferContainerAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledContainerAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.UnfiledRecordFolderAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RetentionScheduleAPI;
/**
* Defines the entire GS Core API
@@ -190,4 +192,11 @@ public class GSCoreAPI extends RMModelRequest
{
return new ActionsExecutionAPI(getRmRestWrapper());
}
public HoldsAPI usingHoldsAPI() { return new HoldsAPI(getRmRestWrapper()); }
public RetentionScheduleAPI usingRetentionScheduleAPI()
{
return new RetentionScheduleAPI(getRmRestWrapper());
}
}

View File

@@ -38,6 +38,8 @@ import static org.springframework.http.HttpMethod.PUT;
import org.alfresco.rest.core.RMRestWrapper;
import org.alfresco.rest.rm.community.model.fileplan.FilePlan;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldCollection;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryCollection;
import org.alfresco.rest.rm.community.requests.RMModelRequest;
@@ -213,4 +215,74 @@ public class FilePlanAPI extends RMModelRequest
parameters));
}
/**
* Creates a hold.
*
* @param holdModel The hold model
* @param filePlanId The identifier of a file plan
* @param parameters The URL parameters to add
* @return The created {@link Hold}
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code filePlanId} is not a valid format or {@code filePlanId} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to add children to {@code filePlanId}</li>
* <li>{@code filePlanIds} does not exist</li>
* <li>new name clashes with an existing node in the current parent container</li>
* </ul>
*/
public Hold createHold(Hold holdModel, String filePlanId, String parameters)
{
mandatoryString("filePlanId", filePlanId);
mandatoryObject("holdModel", holdModel);
return getRmRestWrapper().processModel(Hold.class, requestWithBody(
POST,
toJson(holdModel),
"file-plans/{filePlanId}/holds",
filePlanId,
parameters
));
}
/**
* See {@link #createHold(Hold, String, String)}
*/
public Hold createHold(Hold holdModel, String filePlanId)
{
return createHold(holdModel, filePlanId, EMPTY);
}
/**
* Gets the holds of a file plan.
*
* @param filePlanId The identifier of a file plan
* @param parameters The URL parameters to add
* @return The {@link HoldCollection} for the given {@code filePlanId}
* @throws RuntimeException for the following cases:
* <ul>
* <li>authentication fails</li>
* <li>current user does not have permission to read {@code filePlanId}</li>
* <li>{@code filePlanId} does not exist</li>
*</ul>
*/
public HoldCollection getHolds(String filePlanId, String parameters)
{
mandatoryString("filePlanId", filePlanId);
return getRmRestWrapper().processModels(HoldCollection.class, simpleRequest(
GET,
"file-plans/{filePlanId}/holds?{parameters}",
filePlanId,
parameters
));
}
/**
* See {@link #getHolds(String, String)}
*/
public HoldCollection getHolds(String filePlanId)
{
return getHolds(filePlanId, EMPTY);
}
}

View File

@@ -0,0 +1,446 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.requests.gscore.api;
import static org.alfresco.rest.core.RestRequest.requestWithBody;
import static org.alfresco.rest.core.RestRequest.simpleRequest;
import static org.alfresco.rest.rm.community.util.ParameterCheck.mandatoryObject;
import static org.alfresco.rest.rm.community.util.ParameterCheck.mandatoryString;
import static org.alfresco.rest.rm.community.util.PojoUtility.toJson;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.springframework.http.HttpMethod.DELETE;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.HttpMethod.PUT;
import org.alfresco.rest.core.RMRestWrapper;
import org.alfresco.rest.rm.community.model.hold.BulkBodyCancel;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldBulkOperation;
import org.alfresco.rest.rm.community.model.hold.HoldBulkOperationEntry;
import org.alfresco.rest.rm.community.model.hold.HoldBulkStatus;
import org.alfresco.rest.rm.community.model.hold.HoldBulkStatusCollection;
import org.alfresco.rest.rm.community.model.hold.HoldChild;
import org.alfresco.rest.rm.community.model.hold.HoldChildCollection;
import org.alfresco.rest.rm.community.model.hold.HoldDeletionReason;
import org.alfresco.rest.rm.community.requests.RMModelRequest;
/**
* Holds REST API Wrapper
*
* @author Damian Ujma
*/
public class HoldsAPI extends RMModelRequest
{
/**
* @param rmRestWrapper
*/
public HoldsAPI(RMRestWrapper rmRestWrapper)
{
super(rmRestWrapper);
}
/**
* Gets a hold.
*
* @param holdId The identifier of a hold
* @param parameters The URL parameters to add
* @return The {@link Hold} for the given {@code holdId}
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code holdId} is not a valid format</li>
* <li>authentication fails</li>
* <li>current user does not have permission to read {@code holdId}</li>
* <li>{@code holdId} does not exist</li>
* </ul>
*/
public Hold getHold(String holdId, String parameters)
{
mandatoryString("holdId", holdId);
return getRmRestWrapper().processModel(Hold.class, simpleRequest(
GET,
"holds/{holdId}?{parameters}",
holdId,
parameters
));
}
/**
* See {@link #getHold(String, String)}
*/
public Hold getHold(String holdId)
{
mandatoryString("holdId", holdId);
return getHold(holdId, EMPTY);
}
/**
* Updates a hold.
*
* @param holdModel The hold model which holds the information
* @param holdId The identifier of the hold
* @param parameters The URL parameters to add
* @throws RuntimeException for the following cases:
* <ul>
* <li>the update request is invalid or {@code holdId} is not a valid format or {@code holdModel} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to update {@code holdId}</li>
* <li>{@code holdId} does not exist</li>
* </ul>
*/
public Hold updateHold(Hold holdModel, String holdId, String parameters)
{
mandatoryObject("holdModel", holdModel);
mandatoryString("holdId", holdId);
return getRmRestWrapper().processModel(Hold.class, requestWithBody(
PUT,
toJson(holdModel),
"holds/{holdId}?{parameters}",
holdId,
parameters
));
}
/**
* See {@link #updateHold(Hold, String, String)}
*/
public Hold updateHold(Hold holdModel, String holdId)
{
mandatoryObject("holdModel", holdModel);
mandatoryString("holdId", holdId);
return updateHold(holdModel, holdId, EMPTY);
}
/**
* Deletes a hold.
*
* @param holdId The identifier of a hold
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code holdId} is not a valid format</li>
* <li>authentication fails</li>
* <li>current user does not have permission to delete {@code holdId}</li>
* <li>{@code holdId} does not exist</li>
* </ul>
*/
public void deleteHold(String holdId)
{
mandatoryString("holdId", holdId);
getRmRestWrapper().processEmptyModel(simpleRequest(
DELETE,
"holds/{holdId}",
holdId
));
}
/**
* Deletes a hold and stores a reason for deletion in the audit log.
*
* @param reason The reason for hold deletion
* @param holdId The identifier of a hold
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code holdId} is not a valid format or {@code reason} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to delete {@code holdId}</li>
* <li>{@code holdId} does not exist</li>
* </ul>
*/
public HoldDeletionReason deleteHoldWithReason(HoldDeletionReason reason, String holdId)
{
mandatoryObject("reason", reason);
mandatoryString("holdId", holdId);
return getRmRestWrapper().processModel(HoldDeletionReason.class, requestWithBody(
POST,
toJson(reason),
"holds/{holdId}/delete",
holdId
));
}
/**
* Adds the relationship between a child and a parent hold.
*
* @param holdChild The hold child model
* @param holdId The identifier of a hold
* @param parameters The URL parameters to add
* @return The created {@link Hold}
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code holdId} is not a valid format or {@code holdId} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to add children to {@code holdId}</li>
* <li>{@code holdId} does not exist</li>
* </ul>
*/
public HoldChild addChildToHold(HoldChild holdChild, String holdId, String parameters)
{
mandatoryObject("holdId", holdId);
return getRmRestWrapper().processModel(HoldChild.class, requestWithBody(
POST,
toJson(holdChild),
"holds/{holdId}/children",
holdId,
parameters));
}
/**
* See {@link #addChildToHold(HoldChild, String, String)}
*/
public HoldChild addChildToHold(HoldChild holdChild, String holdId)
{
return addChildToHold(holdChild, holdId, EMPTY);
}
/**
* Gets the children of a hold.
*
* @param holdId The identifier of a hold
* @param parameters The URL parameters to add
* @return The {@link HoldChildCollection} for the given {@code holdId}
* @throws RuntimeException for the following cases:
* <ul>
* <li>authentication fails</li>
* <li>current user does not have permission to read {@code holdId}</li>
* <li>{@code holdId} does not exist</li>
*</ul>
*/
public HoldChildCollection getChildren(String holdId, String parameters)
{
mandatoryString("holdId", holdId);
return getRmRestWrapper().processModels(HoldChildCollection.class, simpleRequest(
GET,
"holds/{holdId}/children",
holdId,
parameters
));
}
/**
* See {@link #getChildren(String, String)}
*/
public HoldChildCollection getChildren(String holdId)
{
return getChildren(holdId, EMPTY);
}
/**
* Deletes the relationship between a child and a parent hold.
*
* @param holdChildId The identifier of hold child
* @param holdId The identifier of a hold
* @param parameters The URL parameters to add
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code holdId} or {@code holdChildId} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to delete children from {@code holdId}</li>
* <li>{@code holdId} does not exist</li>
* </ul>
*/
public void deleteHoldChild(String holdId, String holdChildId, String parameters)
{
mandatoryString("holdId", holdId);
mandatoryString("holdChildId", holdChildId);
getRmRestWrapper().processEmptyModel(simpleRequest(
DELETE,
"holds/{holdId}/children/{holdChildId}",
holdId,
holdChildId,
parameters
));
}
/**
* See {@link #deleteHoldChild(String, String, String)}
*/
public void deleteHoldChild(String holdId, String holdChildId)
{
deleteHoldChild(holdId, holdChildId, EMPTY);
}
/**
* Starts a bulk process for a hold.
*
* @param holdBulkOperation The bulk operation details
* @param hold The identifier of a hold
* @param parameters The URL parameters to add
* @return The {@link HoldBulkOperationEntry} for the started bulk process
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code hold} or {@code holdBulkOperation} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to start a bulk process for {@code hold}</li>
* <li>{@code hold} does not exist</li>
* </ul>
*/
public HoldBulkOperationEntry startBulkProcess(HoldBulkOperation holdBulkOperation, String hold, String parameters)
{
mandatoryObject("holdBulkOperation", holdBulkOperation);
mandatoryString("hold", hold);
return getRmRestWrapper().processModel(HoldBulkOperationEntry.class, requestWithBody(
POST,
toJson(holdBulkOperation),
"holds/{hold}/bulk",
hold,
parameters
));
}
/**
* See {@link #startBulkProcess(HoldBulkOperation, String, String)}
*/
public HoldBulkOperationEntry startBulkProcess(HoldBulkOperation holdBulkOperation, String hold)
{
return startBulkProcess(holdBulkOperation, hold, EMPTY);
}
/**
* Gets the status of a bulk process for a hold.
*
* @param holdId The identifier of a hold
* @param holdBulkStatusId The identifier of a bulk status operation
* @param parameters The URL parameters to add
* @return The {@link HoldBulkStatus} for the given {@code holdId} and {@code holdBulkStatusId}
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code holdId} or {@code holdBulkStatusId} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to get the bulk status for {@code holdId}</li>
* <li>{@code holdId} or {@code holdBulkStatusId} does not exist</li>
* </ul>
*/
public HoldBulkStatus getBulkStatus(String holdId, String holdBulkStatusId, String parameters)
{
mandatoryString("holdId", holdId);
mandatoryString("holdBulkStatusId", holdBulkStatusId);
return getRmRestWrapper().processModel(HoldBulkStatus.class, simpleRequest(
GET,
"holds/{holdId}/bulk-statuses/{holdBulkStatusId}",
holdId,
holdBulkStatusId,
parameters
));
}
/**
* See {@link #getBulkStatus(String, String, String)}
*/
public HoldBulkStatus getBulkStatus(String holdId, String holdBulkStatusId)
{
return getBulkStatus(holdId, holdBulkStatusId, EMPTY);
}
/**
* Gets the statuses of all bulk processes for a hold.
*
* @param holdId The identifier of a hold
* @param parameters The URL parameters to add
* @return The {@link HoldBulkStatusCollection} for the given {@code holdId}
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code holdId} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to get the bulk statuses for {@code holdId}</li>
* <li>{@code holdId} does not exist</li>
* </ul>
*/
public HoldBulkStatusCollection getBulkStatuses(String holdId, String parameters)
{
mandatoryString("holdId", holdId);
return getRmRestWrapper().processModels(HoldBulkStatusCollection.class, simpleRequest(
GET,
"holds/{holdId}/bulk-statuses",
holdId,
parameters
));
}
/**
* See {@link #getBulkStatuses(String, String)}
*/
public HoldBulkStatusCollection getBulkStatuses(String holdId)
{
return getBulkStatuses(holdId, EMPTY);
}
/**
* Cancels a bulk operation for a hold.
*
* @param holdId The identifier of a hold
* @param bulkStatusId The identifier of a bulk status operation
* @param bulkBodyCancel The bulk body cancel model
* @param parameters The URL parameters to add
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code holdId}, {@code bulkStatusId} or {@code bulkBodyCancel} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to cancel the bulk operation for {@code bulkStatusId}</li>
* <li>{@code holdId} or {@code bulkStatusId} does not exist</li>
* </ul>
*/
public void cancelBulkOperation(String holdId, String bulkStatusId, BulkBodyCancel bulkBodyCancel, String parameters)
{
mandatoryString("holdId", holdId);
mandatoryString("bulkStatusId", bulkStatusId);
mandatoryObject("bulkBodyCancel", bulkBodyCancel);
getRmRestWrapper().processEmptyModel(requestWithBody(
POST,
toJson(bulkBodyCancel),
"holds/{holdId}/bulk-statuses/{bulkStatusId}/cancel",
holdId,
bulkStatusId,
parameters
));
}
/**
* See {@link #cancelBulkOperation(String, String, BulkBodyCancel, String)}
*/
public void cancelBulkOperation(String holdId, String bulkStatusId, BulkBodyCancel bulkBodyCancel)
{
mandatoryString("holdId", holdId);
mandatoryString("bulkStatusId", bulkStatusId);
mandatoryObject("bulkBodyCancel", bulkBodyCancel);
cancelBulkOperation(holdId, bulkStatusId, bulkBodyCancel, EMPTY);
}
}

View File

@@ -0,0 +1,198 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.requests.gscore.api;
import org.alfresco.rest.core.RMRestWrapper;
import org.alfresco.rest.rm.community.model.retentionschedule.RetentionSchedule;
import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleActionDefinition;
import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleCollection;
import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleStepCollection;
import org.alfresco.rest.rm.community.requests.RMModelRequest;
import static org.alfresco.rest.core.RestRequest.requestWithBody;
import static org.alfresco.rest.core.RestRequest.simpleRequest;
import static org.alfresco.rest.rm.community.util.ParameterCheck.mandatoryObject;
import static org.alfresco.rest.rm.community.util.ParameterCheck.mandatoryString;
import static org.alfresco.rest.rm.community.util.PojoUtility.toJson;
import static org.apache.commons.lang3.StringUtils.EMPTY;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;
public class RetentionScheduleAPI extends RMModelRequest
{
/**
* @param rmRestWrapper
*/
public RetentionScheduleAPI(RMRestWrapper rmRestWrapper)
{
super(rmRestWrapper);
}
/**
* Creates a retention schedule.
*
* @param retentionScheduleModel The retentionSchedule model
* @param recordCategoryId The identifier of a record category
* @param parameters The URL parameters to add
* @return The created {@link RetentionSchedule}
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code recordCategoryId} is not a valid format or {@code recordCategoryId} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to add children to {@code recordCategoryId}</li>
* <li>{@code recordCategoryId} does not exist</li>
* <li>new name clashes with an existing node in the current parent container</li>
* </ul>
*/
public RetentionSchedule createRetentionSchedule(RetentionSchedule retentionScheduleModel, String recordCategoryId, String parameters)
{
mandatoryString("recordCategoryId", recordCategoryId);
mandatoryObject("retentionScheduleModel", retentionScheduleModel);
return getRmRestWrapper().processModel(RetentionSchedule.class, requestWithBody(
POST,
toJson(retentionScheduleModel),
"record-categories/{recordCategoryId}/retention-schedules",
recordCategoryId,
parameters
));
}
/**
* See {@link #createRetentionSchedule(RetentionSchedule, String, String)}
*/
public RetentionSchedule createRetentionSchedule(RetentionSchedule retentionScheduleModel, String recordCategoryId)
{
return createRetentionSchedule(retentionScheduleModel, recordCategoryId, EMPTY);
}
/**
* Gets the retentionSchedule of a record category.
*
* @param recordCategoryId The identifier of a record category
* @param parameters The URL parameters to add
* @return The {@link RetentionSchedule} for the given {@code recordCategoryId}
* @throws RuntimeException for the following cases:
* <ul>
* <li>authentication fails</li>
* <li>current user does not have permission to read {@code recordCategoryId}</li>
* <li>{@code recordCategoryId} does not exist</li>
*</ul>
*/
public RetentionScheduleCollection getRetentionSchedule(String recordCategoryId, String parameters)
{
mandatoryString("recordCategoryId", recordCategoryId);
return getRmRestWrapper().processModels(RetentionScheduleCollection.class, simpleRequest(
GET,
"record-categories/{recordCategoryId}/retention-schedules?{parameters}",
recordCategoryId,
parameters
));
}
/**
* See {@link #getRetentionSchedule(String, String)}
*/
public RetentionScheduleCollection getRetentionSchedule(String recordCategoryId)
{
return getRetentionSchedule(recordCategoryId, EMPTY);
}
/**
* Creates a step in the retention schedule.
*
* @param retentionScheduleActionDefinition The retentionScheduleActionDefinition model
* @param retentionScheduleId The identifier of a retention schedule id
* @param parameters The URL parameters to add
* @return The created {@link RetentionScheduleActionDefinition}
* @throws RuntimeException for the following cases:
* <ul>
* <li>{@code retentionScheduleId} is not a valid format or {@code retentionScheduleId} is invalid</li>
* <li>authentication fails</li>
* <li>current user does not have permission to add children to {@code retentionScheduleId}</li>
* <li>{@code retentionScheduleId} does not exist</li>
* <li>new name clashes with an existing node in the current parent container</li>
* </ul>
*/
public RetentionScheduleActionDefinition createRetentionScheduleStep(RetentionScheduleActionDefinition retentionScheduleActionDefinition, String retentionScheduleId, String parameters)
{
mandatoryString("retentionScheduleId", retentionScheduleId);
mandatoryObject("retentionScheduleActionDefinition", retentionScheduleActionDefinition);
return getRmRestWrapper().processModel(RetentionScheduleActionDefinition.class, requestWithBody(
POST,
toJson(retentionScheduleActionDefinition),
"retention-schedules/{retentionScheduleId}/retention-steps",
retentionScheduleId,
parameters
));
}
/**
* See {@link #createRetentionScheduleStep(RetentionScheduleActionDefinition, String)} (RetentionSchedule, String, String)}
*/
public RetentionScheduleActionDefinition createRetentionScheduleStep(RetentionScheduleActionDefinition retentionScheduleActionDefinition, String retentionScheduleId)
{
return createRetentionScheduleStep(retentionScheduleActionDefinition, retentionScheduleId, EMPTY);
}
/**
* Gets the retentionSchedule of a record category.
*
* @param retentionScheduleId The identifier of a record category
* @param parameters The URL parameters to add
* @return The {@link RetentionScheduleActionDefinition} for the given {@code recordCategoryId}
* @throws RuntimeException for the following cases:
* <ul>
* <li>authentication fails</li>
* <li>current user does not have permission to read {@code recordCategoryId}</li>
* <li>{@code recordCategoryId} does not exist</li>
*</ul>
*/
public RetentionScheduleStepCollection getRetentionScheduleStep(String retentionScheduleId, String parameters)
{
mandatoryString("retentionScheduleId", retentionScheduleId);
return getRmRestWrapper().processModels(RetentionScheduleStepCollection.class, simpleRequest(
GET,
"retention-schedules/{retentionScheduleId}/retention-steps?{parameters}",
retentionScheduleId,
parameters
));
}
/**
* See {@link #getRetentionScheduleStep(String, String)}
*/
public RetentionScheduleStepCollection getRetentionScheduleStep(String recordCategoryId)
{
return getRetentionScheduleStep(recordCategoryId, EMPTY);
}
}

View File

@@ -36,7 +36,7 @@ import java.util.stream.Collectors;
import org.alfresco.rest.core.v0.APIUtils;
import org.alfresco.rest.core.v0.BaseAPI;
import org.alfresco.rest.rm.community.model.hold.HoldEntry;
import org.alfresco.rest.rm.community.model.hold.v0.HoldEntry;
import org.alfresco.rest.rm.community.util.PojoUtility;
import org.alfresco.utility.model.UserModel;
import org.apache.http.HttpResponse;

View File

@@ -31,18 +31,18 @@ import static java.util.Arrays.asList;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.ADD_TO_HOLD;
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.RMSiteUtil.FILE_PLAN_PATH;
import static org.alfresco.utility.Utility.buildPath;
import static org.alfresco.utility.Utility.removeLastSlash;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.apache.commons.httpclient.HttpStatus.SC_INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.google.common.collect.ImmutableMap;
@@ -50,12 +50,13 @@ import com.google.common.collect.ImmutableMap;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldChild;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.user.UserPermissions;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.v0.HoldsAPI;
import org.alfresco.rest.v0.service.RMAuditService;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.test.AlfrescoTest;
@@ -85,8 +86,6 @@ public class AuditAddToHoldTests extends BaseRMRestTest
@Autowired
private RMAuditService rmAuditService;
@Autowired
private HoldsAPI holdsAPI;
@Autowired
private RoleService roleService;
private UserModel rmAdmin, rmManagerNoReadOnHold, rmManagerNoReadOnNode;
@@ -94,17 +93,22 @@ public class AuditAddToHoldTests extends BaseRMRestTest
private RecordCategory recordCategory;
private RecordCategoryChild recordFolder;
private List<AuditEntry> auditEntries;
private final List<String> holdsList = asList(HOLD1, HOLD2);
private List<String> holdsListRef = new ArrayList<>();
private String hold1NodeRef;
private String hold2NodeRef;
@BeforeClass (alwaysRun = true)
public void preconditionForAuditAddToHoldTests()
{
STEP("Create 2 holds.");
hold1NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(),
getAdminUser().getPassword(), HOLD1, HOLD_REASON, HOLD_DESCRIPTION);
String hold2NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION);
hold1NodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(HOLD1).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
hold2NodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(HOLD2).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
holdsListRef = asList(hold1NodeRef, hold2NodeRef);
STEP("Create a new record category with a record folder.");
@@ -169,7 +173,8 @@ public class AuditAddToHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Add node to hold.");
holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), nodeId, HOLD1);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(nodeId).build(), hold1NodeRef);
STEP("Check the audit log contains the entry for the add to hold event.");
rmAuditService.checkAuditLogForEvent(getAdminUser(), ADD_TO_HOLD, rmAdmin, nodeName, nodePath,
@@ -191,9 +196,8 @@ public class AuditAddToHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Try to add the record to a hold by an user with no rights.");
holdsAPI.addItemsToHolds(rmManagerNoReadOnHold.getUsername(), rmManagerNoReadOnHold.getPassword(),
SC_INTERNAL_SERVER_ERROR, Collections.singletonList(recordToBeAdded.getId()),
Collections.singletonList(hold1NodeRef));
getRestAPIFactory().getHoldsAPI(rmManagerNoReadOnHold).addChildToHold(HoldChild.builder().id(recordToBeAdded.getId()).build(), hold1NodeRef);
assertStatusCode(FORBIDDEN);
STEP("Check the audit log doesn't contain the entry for the unsuccessful add to hold.");
assertTrue("The list of events should not contain Add to Hold entry ",
@@ -215,7 +219,7 @@ public class AuditAddToHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Add record folder to hold.");
holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), notEmptyRecFolder.getId(), HOLD1);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(notEmptyRecFolder.getId()).build(), hold1NodeRef);
auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), ADD_TO_HOLD);
@@ -239,8 +243,9 @@ public class AuditAddToHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Add record to multiple holds.");
holdsAPI.addItemsToHolds(rmAdmin.getUsername(), rmAdmin.getPassword(),
Collections.singletonList(recordToBeAdded.getId()), holdsList);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(recordToBeAdded.getId()).build(), hold1NodeRef);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(recordToBeAdded.getId()).build(), hold2NodeRef);
auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), ADD_TO_HOLD);
@@ -268,7 +273,7 @@ public class AuditAddToHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Add file to hold.");
holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), contentToBeAdded.getNodeRefWithoutVersion(), HOLD1);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(contentToBeAdded.getNodeRefWithoutVersion()).build(), hold1NodeRef);
STEP("Check that an user with no Read permissions can't see the entry for the add to hold event.");
assertTrue("The list of events should not contain Add to Hold entry ",
@@ -289,7 +294,7 @@ public class AuditAddToHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Add file to hold.");
holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), contentToBeAdded.getNodeRefWithoutVersion(), HOLD1);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(contentToBeAdded.getNodeRefWithoutVersion()).build(), hold1NodeRef);
auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(rmManagerNoReadOnHold, ADD_TO_HOLD);
@@ -304,7 +309,8 @@ public class AuditAddToHoldTests extends BaseRMRestTest
@AfterClass (alwaysRun = true)
public void cleanUpAuditAddToHoldTests()
{
holdsListRef.forEach(holdRef -> holdsAPI.deleteHold(getAdminUser(), holdRef));
holdsListRef.forEach(holdRef -> getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(holdRef));
dataSite.usingAdmin().deleteSite(privateSite);
asList(rmAdmin, rmManagerNoReadOnHold, rmManagerNoReadOnNode).forEach(user -> getDataUser().usingAdmin().deleteUser(user));
deleteRecordCategory(recordCategory.getId());

View File

@@ -31,9 +31,10 @@ import static java.util.Arrays.asList;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.CREATE_HOLD;
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.utility.report.log.Step.STEP;
import static org.apache.commons.httpclient.HttpStatus.SC_INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.CONFLICT;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
@@ -44,8 +45,8 @@ import com.google.common.collect.ImmutableMap;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.v0.HoldsAPI;
import org.alfresco.rest.v0.service.RMAuditService;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.test.AlfrescoTest;
@@ -73,8 +74,6 @@ public class AuditCreateHoldTests extends BaseRMRestTest
@Autowired
private RMAuditService rmAuditService;
@Autowired
private HoldsAPI holdsAPI;
@Autowired
private RoleService roleService;
private UserModel rmAdmin, rmManager;
@@ -102,8 +101,10 @@ public class AuditCreateHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Create a new hold.");
String hold1NodeRef = holdsAPI.createHoldAndGetNodeRef(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD1,
HOLD_REASON, HOLD_DESCRIPTION);
String hold1NodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(HOLD1).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
holdsListRef.add(hold1NodeRef);
STEP("Check the audit log contains the entry for the created hold with the hold details.");
rmAuditService.checkAuditLogForEvent(getAdminUser(), CREATE_HOLD, rmAdmin, HOLD1,
@@ -120,13 +121,18 @@ public class AuditCreateHoldTests extends BaseRMRestTest
public void createHoldEventIsNotAuditedForExistingHold()
{
STEP("Create a new hold.");
String hold2NodeRef = holdsAPI.createHoldAndGetNodeRef(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION);
String hold2NodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(HOLD2).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
holdsListRef.add(hold2NodeRef);
rmAuditService.clearAuditLog();
STEP("Try to create again the same hold and expect action to fail.");
holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION,
SC_INTERNAL_SERVER_ERROR);
getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(HOLD2).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
assertStatusCode(CONFLICT);
STEP("Check the audit log doesn't contain the entry for the second create hold event.");
assertTrue("The list of events should not contain Create Hold entry ",
@@ -145,13 +151,17 @@ public class AuditCreateHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Create a new hold.");
holdsAPI.createHold(rmAdmin.getUsername(), rmAdmin.getPassword(), holdName, HOLD_REASON, HOLD_DESCRIPTION);
String nodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(holdName).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS).getId();
STEP("Get the list of audit entries for the create hold event.");
List<AuditEntry> auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), CREATE_HOLD);
STEP("Delete the created hold.");
holdsAPI.deleteHold(rmAdmin.getUsername(), rmAdmin.getPassword(), holdName);
getRestAPIFactory()
.getHoldsAPI(rmAdmin)
.deleteHold(nodeRef);
STEP("Get again the list of audit entries for the create hold event.");
List<AuditEntry> auditEntriesAfterDelete = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), CREATE_HOLD);
@@ -171,8 +181,10 @@ public class AuditCreateHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Create a new hold.");
String hold3NodeRef = holdsAPI.createHoldAndGetNodeRef(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD3,
HOLD_REASON, HOLD_DESCRIPTION);
String hold3NodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(HOLD3).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS).getId();
holdsListRef.add(hold3NodeRef);
STEP("Check that an user with no Read permissions over the hold can't see the entry for the create hold event");
@@ -183,7 +195,7 @@ public class AuditCreateHoldTests extends BaseRMRestTest
@AfterClass (alwaysRun = true)
public void cleanUpAuditCreateHoldTests()
{
holdsListRef.forEach(holdRef -> holdsAPI.deleteHold(getAdminUser(), holdRef));
holdsListRef.forEach(holdRef -> getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHold(holdRef));
asList(rmAdmin, rmManager).forEach(user -> getDataUser().usingAdmin().deleteUser(user));
}
}

View File

@@ -31,18 +31,20 @@ import static java.util.Arrays.asList;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.DELETE_HOLD;
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.utility.report.log.Step.STEP;
import static org.apache.commons.httpclient.HttpStatus.SC_INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.testng.AssertJUnit.assertTrue;
import java.util.Collections;
import java.util.List;
import com.google.common.collect.ImmutableMap;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldDeletionReason;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.v0.HoldsAPI;
import org.alfresco.rest.v0.service.RMAuditService;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.test.AlfrescoTest;
@@ -62,14 +64,13 @@ import org.testng.annotations.Test;
public class AuditDeleteHoldTests extends BaseRMRestTest
{
private final String PREFIX = generateTestPrefix(AuditDeleteHoldTests.class);
private final String HOLD = PREFIX + "holdToBeDeleted";
private final String HOLD2 = PREFIX + "deleteHold";
private final String hold = PREFIX + "holdToBeDeleted";
private final String hold2 = PREFIX + "deleteHold";
private final String hold3 = PREFIX + "deleteHoldWithReason";
@Autowired
private RMAuditService rmAuditService;
@Autowired
private HoldsAPI holdsAPI;
@Autowired
private RoleService roleService;
private UserModel rmAdmin, rmManager;
@@ -79,8 +80,10 @@ public class AuditDeleteHoldTests extends BaseRMRestTest
public void preconditionForAuditDeleteHoldTests()
{
STEP("Create a new hold.");
holdNodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD,
HOLD_REASON, HOLD_DESCRIPTION);
holdNodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(hold).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
STEP("Create 2 users with different permissions for the created hold.");
rmAdmin = roleService.createUserWithRMRole(UserRoles.ROLE_RM_ADMIN.roleId);
@@ -99,17 +102,51 @@ public class AuditDeleteHoldTests extends BaseRMRestTest
public void deleteHoldEventIsAudited()
{
STEP("Create a new hold.");
String holdRef = holdsAPI.createHoldAndGetNodeRef(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD2,
HOLD_REASON, HOLD_DESCRIPTION);
String holdRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(hold2).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
rmAuditService.clearAuditLog();
STEP("Delete the created hold.");
holdsAPI.deleteHold(rmAdmin, holdRef);
getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHold(holdRef);
STEP("Check the audit log contains the entry for the deleted hold with the hold details.");
rmAuditService.checkAuditLogForEvent(getAdminUser(), DELETE_HOLD, rmAdmin, HOLD2,
Collections.singletonList(ImmutableMap.of("new", "", "previous", HOLD2, "name", "Hold Name")));
rmAuditService.checkAuditLogForEvent(getAdminUser(), DELETE_HOLD, rmAdmin, hold2,
List.of(ImmutableMap.of("new", "", "previous", hold2, "name", "Hold Name"),
ImmutableMap.of("new", "", "previous", "", "name", "Hold deletion reason")));
}
/**
* Given a hold is deleted with a reason
* When I view the audit log
* Then an entry has been created in the audit log which contains the following:
* name of the hold
* hold deletion reason
* user who deleted the hold
* date the delete occurred
*/
@Test
public void deleteHoldWithReasonEventIsAudited()
{
STEP("Create a new hold.");
String holdRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(hold3).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
String deletionReason = "Test reason";
rmAuditService.clearAuditLog();
STEP("Delete the created hold with a reason.");
getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldWithReason(HoldDeletionReason.builder().reason(deletionReason).build(), holdRef);
STEP("Check the audit log contains the entry for the deleted hold with the hold details.");
rmAuditService.checkAuditLogForEvent(getAdminUser(), DELETE_HOLD, rmAdmin, hold3,
List.of(ImmutableMap.of("new", "", "previous", hold3, "name", "Hold Name"),
ImmutableMap.of("new", "", "previous", deletionReason, "name", "Hold deletion reason")));
}
/**
@@ -123,7 +160,8 @@ public class AuditDeleteHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Try to delete a hold by an user with no Read permissions over the hold.");
holdsAPI.deleteHold(rmManager.getUsername(), rmManager.getPassword(), holdNodeRef, SC_INTERNAL_SERVER_ERROR);
getRestAPIFactory().getHoldsAPI(rmManager).deleteHold(holdNodeRef);
assertStatusCode(FORBIDDEN);
STEP("Check the audit log doesn't contain the entry for the unsuccessful delete hold.");
assertTrue("The list of events should not contain Delete Hold entry ",
@@ -133,7 +171,7 @@ public class AuditDeleteHoldTests extends BaseRMRestTest
@AfterClass (alwaysRun = true)
public void cleanUpAuditDeleteHoldTests()
{
holdsAPI.deleteHold(getAdminUser(), holdNodeRef);
getRestAPIFactory().getHoldsAPI(rmManager).deleteHold(holdNodeRef);
asList(rmAdmin, rmManager).forEach(user -> getDataUser().usingAdmin().deleteUser(user));
}
}

View File

@@ -25,10 +25,14 @@
* #L%
*/
package org.alfresco.rest.rm.community.audit;
import static java.util.Arrays.asList;
import static org.alfresco.rest.rm.community.base.TestData.*;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.ADD_TO_HOLD;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.REMOVE_FROM_HOLD;
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.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
@@ -37,20 +41,22 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.core.IsNot.not;
import static org.springframework.http.HttpStatus.CREATED;
import static org.testng.AssertJUnit.*;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
import java.util.Collections;
import java.util.List;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
import org.alfresco.rest.rm.community.model.audit.AuditEvents;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldChild;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolder;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.v0.HoldsAPI;
import org.alfresco.rest.v0.service.RMAuditService;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.utility.model.FileModel;
@@ -69,8 +75,6 @@ public class AuditHoldsTest extends BaseRMRestTest {
@Autowired
private RMAuditService rmAuditService;
@Autowired
private HoldsAPI holdsAPI;
@Autowired
private RoleService roleService;
private UserModel rmAdmin;
private RecordCategory recordCategory;
@@ -85,8 +89,11 @@ public class AuditHoldsTest extends BaseRMRestTest {
rmAdmin = roleService.createUserWithRMRole(UserRoles.ROLE_RM_ADMIN.roleId);
STEP("Create a hold");
hold1NodeRef = holdsAPI.createHoldAndGetNodeRef(rmAdmin.getUsername(), rmAdmin.getPassword(), HOLD1, HOLD_REASON,
HOLD_DESCRIPTION);
hold1NodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(HOLD1).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
STEP("Create a collaboration site with a test file.");
publicSite = dataSite.usingAdmin().createPublicRandomSite();
@@ -101,9 +108,11 @@ public class AuditHoldsTest extends BaseRMRestTest {
STEP("Add some items to the hold, then remove them from the hold");
final List<String> itemsList = asList(testFile.getNodeRefWithoutVersion(), recordToBeAdded.getId(), recordFolder2.getId());
final List<String> holdsList = Collections.singletonList(HOLD1);
holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), recordToBeAdded.getId(), HOLD1);
holdsAPI.removeItemsFromHolds(rmAdmin.getUsername(), rmAdmin.getPassword(), itemsList, holdsList);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(recordToBeAdded.getId()).build(), hold1NodeRef);
for(String childId : itemsList)
{
getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold1NodeRef, childId);
}
STEP("Delete the record folder that was held");
getRestAPIFactory().getRecordFolderAPI().deleteRecordFolder(recordFolder2.getId());

View File

@@ -31,18 +31,18 @@ import static java.util.Arrays.asList;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
import static org.alfresco.rest.rm.community.model.audit.AuditEvents.REMOVE_FROM_HOLD;
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.RMSiteUtil.FILE_PLAN_PATH;
import static org.alfresco.utility.Utility.buildPath;
import static org.alfresco.utility.Utility.removeLastSlash;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.apache.commons.httpclient.HttpStatus.SC_INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.google.common.collect.ImmutableMap;
@@ -50,12 +50,13 @@ import com.google.common.collect.ImmutableMap;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.audit.AuditEntry;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldChild;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.user.UserPermissions;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.v0.HoldsAPI;
import org.alfresco.rest.v0.service.RMAuditService;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.test.AlfrescoTest;
@@ -86,8 +87,6 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
@Autowired
private RMAuditService rmAuditService;
@Autowired
private HoldsAPI holdsAPI;
@Autowired
private RoleService roleService;
private UserModel rmAdmin, rmManagerNoReadOnHold, rmManagerNoReadOnNode;
@@ -96,10 +95,11 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
private RecordCategoryChild recordFolder, heldRecordFolder;
private Record heldRecord;
private List<AuditEntry> auditEntries;
private final List<String> holdsList = asList(HOLD1, HOLD2, HOLD3);
private List<String> holdsListRef = new ArrayList<>();
private FileModel heldContent;
private String hold1NodeRef;
private String hold2NodeRef;
private String hold3NodeRef;
@BeforeClass (alwaysRun = true)
public void preconditionForAuditRemoveFromHoldTests()
@@ -111,10 +111,18 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
privateSite = dataSite.usingUser(rmAdmin).createPrivateRandomSite();
STEP("Create new holds.");
hold1NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(),
HOLD1, HOLD_REASON, HOLD_DESCRIPTION);
String hold2NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD2, HOLD_REASON, HOLD_DESCRIPTION);
String hold3NodeRef = holdsAPI.createHoldAndGetNodeRef(getAdminUser().getUsername(), getAdminUser().getPassword(), HOLD3, HOLD_REASON, HOLD_DESCRIPTION);
hold1NodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(HOLD1).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
hold2NodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(HOLD2).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
hold3NodeRef = getRestAPIFactory()
.getFilePlansAPI(rmAdmin)
.createHold(Hold.builder().name(HOLD3).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), FILE_PLAN_ALIAS)
.getId();
holdsListRef = asList(hold1NodeRef, hold2NodeRef, hold3NodeRef);
STEP("Create a new record category with a record folder.");
@@ -127,9 +135,12 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
heldRecordFolder = createRecordFolder(recordCategory.getId(), PREFIX + "heldRecFolder");
heldRecord = createElectronicRecord(recordFolder.getId(), PREFIX + "record");
holdsAPI.addItemsToHolds(getAdminUser().getUsername(), getAdminUser().getPassword(),
asList(heldContent.getNodeRefWithoutVersion(), heldRecordFolder.getId(), heldRecord.getId()),
holdsList);
holdsListRef.forEach(holdRef ->
{
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(heldContent.getNodeRefWithoutVersion()).build(), holdRef);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(heldRecordFolder.getId()).build(), holdRef);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(heldRecord.getId()).build(), holdRef);
});
STEP("Create users without rights to remove content from a hold.");
rmManagerNoReadOnHold = roleService.createUserWithSiteRoleRMRoleAndPermission(privateSite,
@@ -179,7 +190,7 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Remove node from hold.");
holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), nodeId, HOLD3);
getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold3NodeRef, nodeId);
STEP("Check the audit log contains the entry for the remove from hold event.");
rmAuditService.checkAuditLogForEvent(getAdminUser(), REMOVE_FROM_HOLD, rmAdmin, nodeName, nodePath,
@@ -198,9 +209,8 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Try to remove the record from a hold by an user with no rights.");
holdsAPI.removeItemsFromHolds(rmManagerNoReadOnHold.getUsername(), rmManagerNoReadOnHold.getPassword(),
SC_INTERNAL_SERVER_ERROR, Collections.singletonList(heldRecord.getId()),
Collections.singletonList(hold1NodeRef));
getRestAPIFactory().getHoldsAPI(rmManagerNoReadOnHold).deleteHoldChild(hold1NodeRef, heldRecord.getId());
assertStatusCode(FORBIDDEN);
STEP("Check the audit log doesn't contain the entry for the unsuccessful remove from hold.");
assertTrue("The list of events should not contain remove from hold entry ",
@@ -220,12 +230,12 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
Record record = createElectronicRecord(notEmptyRecFolder.getId(), PREFIX + "record");
STEP("Add the record folder to a hold.");
holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), notEmptyRecFolder.getId(), HOLD1);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(notEmptyRecFolder.getId()).build(), hold1NodeRef);
rmAuditService.clearAuditLog();
STEP("Remove record folder from hold.");
holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), notEmptyRecFolder.getId(), HOLD1);
getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold1NodeRef, notEmptyRecFolder.getId());
STEP("Get the list of audit entries for the remove from hold event.");
auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), REMOVE_FROM_HOLD);
@@ -247,8 +257,8 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
rmAuditService.clearAuditLog();
STEP("Remove record folder from multiple holds.");
holdsAPI.removeItemsFromHolds(rmAdmin.getUsername(), rmAdmin.getPassword(),
Collections.singletonList(heldRecordFolder.getId()), asList(HOLD1, HOLD2));
getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold1NodeRef, heldRecordFolder.getId());
getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold2NodeRef, heldRecordFolder.getId());
STEP("Get the list of audit entries for the remove from hold event.");
auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(getAdminUser(), REMOVE_FROM_HOLD);
@@ -275,12 +285,12 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
STEP("Add content to a hold.");
FileModel heldFile = dataContent.usingAdmin().usingSite(privateSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldFile.getNodeRefWithoutVersion(), HOLD1);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(heldFile.getNodeRefWithoutVersion()).build(), hold1NodeRef);
rmAuditService.clearAuditLog();
STEP("Remove held content from the hold.");
holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldFile.getNodeRefWithoutVersion(), HOLD1);
getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold1NodeRef, heldFile.getNodeRefWithoutVersion());
STEP("Check that an user with no Read permissions can't see the entry for the remove from hold event.");
assertTrue("The list of events should not contain Remove from Hold entry ",
@@ -298,12 +308,12 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
STEP("Add content to a hold.");
FileModel heldFile = dataContent.usingAdmin().usingSite(privateSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
holdsAPI.addItemToHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldFile.getNodeRefWithoutVersion(), HOLD1);
getRestAPIFactory().getHoldsAPI(rmAdmin).addChildToHold(HoldChild.builder().id(heldFile.getNodeRefWithoutVersion()).build(), hold1NodeRef);
rmAuditService.clearAuditLog();
STEP("Remove held content from the hold.");
holdsAPI.removeItemFromHold(rmAdmin.getUsername(), rmAdmin.getPassword(), heldFile.getNodeRefWithoutVersion(), HOLD1);
getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHoldChild(hold1NodeRef, heldFile.getNodeRefWithoutVersion());
auditEntries = rmAuditService.getAuditEntriesFilteredByEvent(rmManagerNoReadOnHold, REMOVE_FROM_HOLD);
@@ -318,7 +328,7 @@ public class AuditRemoveFromHoldTests extends BaseRMRestTest
@AfterClass (alwaysRun = true)
public void cleanUpAuditRemoveFromHoldTests()
{
holdsListRef.forEach(holdRef -> holdsAPI.deleteHold(getAdminUser(), holdRef));
holdsListRef.forEach(holdRef -> getRestAPIFactory().getHoldsAPI(rmAdmin).deleteHold(holdRef));
dataSite.usingAdmin().deleteSite(privateSite);
asList(rmAdmin, rmManagerNoReadOnHold, rmManagerNoReadOnNode).forEach(user -> getDataUser().usingAdmin().deleteUser(user));
deleteRecordCategory(recordCategory.getId());

View File

@@ -60,12 +60,15 @@ import static org.testng.Assert.fail;
import static org.testng.AssertJUnit.assertEquals;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.base.DataProviderClass;
import org.alfresco.rest.rm.community.model.fileplan.FilePlan;
import org.alfresco.rest.rm.community.model.fileplan.FilePlanProperties;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldCollection;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryCollection;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryProperties;
@@ -514,5 +517,97 @@ public class FilePlanTests extends BaseRMRestTest
);
}
/**
* <pre>
* Given that a file plan exists
* When I ask the API to create a hold
* Then it is created
* </pre>
*/
@Test
public void createHolds()
{
String holdName = "Hold" + getRandomAlphanumeric();
String holdDescription = "Description" + getRandomAlphanumeric();
String holdReason = "Reason" + getRandomAlphanumeric();
// Create the hold
Hold hold = Hold.builder()
.name(holdName)
.description(holdDescription)
.reason(holdReason)
.build();
Hold createdHold = getRestAPIFactory().getFilePlansAPI()
.createHold(hold, FILE_PLAN_ALIAS);
// Verify the status code
assertStatusCode(CREATED);
assertEquals(createdHold.getName(), holdName);
assertEquals(createdHold.getDescription(), holdDescription);
assertEquals(createdHold.getReason(), holdReason);
assertNotNull(createdHold.getId());
}
@Test
public void listHolds()
{
// Delete all holds
getRestAPIFactory().getFilePlansAPI().getHolds(FILE_PLAN_ALIAS).getEntries().forEach(holdEntry ->
getRestAPIFactory().getHoldsAPI().deleteHold(holdEntry.getEntry().getId()));
// Add holds
List<Hold> filePlanHolds = new ArrayList<>();
for (int i = 0; i < NUMBER_OF_CHILDREN; i++)
{
String holdName = "Hold name " + getRandomAlphanumeric();
String holdDescription = "Hold Description " + getRandomAlphanumeric();
String holdReason = "Reason " + getRandomAlphanumeric();
// Create a hold
Hold hold = Hold.builder()
.name(holdName)
.description(holdDescription)
.reason(holdReason)
.build();
Hold createdHold = getRestAPIFactory().getFilePlansAPI()
.createHold(hold, FILE_PLAN_ALIAS);
assertNotNull(createdHold.getId());
filePlanHolds.add(createdHold);
}
// Get holds of a file plan
HoldCollection holdCollection = getRestAPIFactory().getFilePlansAPI()
.getHolds(FILE_PLAN_ALIAS);
// Check status code
assertStatusCode(OK);
// Check holds against created list
holdCollection.getEntries().forEach(c ->
{
Hold hold = c.getEntry();
String holdId = hold.getId();
assertNotNull(holdId);
logger.info("Checking hold " + holdId);
try
{
// Find this hold in created holds list
Hold createdHold = filePlanHolds.stream()
.filter(child -> child.getId().equals(holdId))
.findFirst()
.orElseThrow();
assertEquals(createdHold.getName(), hold.getName());
assertEquals(createdHold.getDescription(), hold.getDescription());
assertEquals(createdHold.getReason(), hold.getReason());
}
catch (NoSuchElementException e)
{
fail("No child element for " + hold);
}
}
);
}
}

View File

@@ -0,0 +1,614 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.hold;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.awaitility.Awaitility.await;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.http.HttpStatus.ACCEPTED;
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 static org.springframework.http.HttpStatus.UNAUTHORIZED;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.dataprep.ContentActions;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.hold.BulkBodyCancel;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldBulkOperation;
import org.alfresco.rest.rm.community.model.hold.HoldBulkOperation.HoldBulkOperationType;
import org.alfresco.rest.rm.community.model.hold.HoldBulkOperationEntry;
import org.alfresco.rest.rm.community.model.hold.HoldBulkStatus;
import org.alfresco.rest.rm.community.model.hold.HoldBulkStatusCollection;
import org.alfresco.rest.rm.community.model.hold.HoldBulkStatusEntry;
import org.alfresco.rest.rm.community.model.hold.HoldChild;
import org.alfresco.rest.rm.community.model.hold.HoldChildEntry;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.search.RestRequestQueryModel;
import org.alfresco.rest.search.SearchRequest;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* API tests for adding items to holds via the bulk process
*/
public class AddToHoldsBulkV1Tests extends BaseRMRestTest
{
private static final String ACCESS_DENIED_ERROR_MESSAGE = "Access Denied. You do not have the appropriate " +
"permissions to perform this operation.";
private static final int NUMBER_OF_FILES = 5;
private final List<FileModel> addedFiles = new ArrayList<>();
private final List<UserModel> users = new ArrayList<>();
private final List<Hold> holds = new ArrayList<>();
private Hold hold;
private Hold hold2;
private Hold hold3;
private FolderModel rootFolder;
private HoldBulkOperation holdBulkOperation;
@Autowired
private RoleService roleService;
@Autowired
private ContentActions contentActions;
@BeforeClass(alwaysRun = true)
public void preconditionForAddContentToHold()
{
STEP("Create a hold.");
hold = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
holds.add(hold);
STEP("Create test files.");
testSite = dataSite.usingAdmin().createPublicRandomSite();
rootFolder = dataContent.usingAdmin().usingSite(testSite).createFolder();
FolderModel folder1 = dataContent.usingAdmin().usingResource(rootFolder).createFolder();
FolderModel folder2 = dataContent.usingAdmin().usingResource(folder1).createFolder();
// Add files to subfolders in the site
for (int i = 0; i < NUMBER_OF_FILES; i++)
{
FileModel documentHeld = dataContent.usingAdmin()
.usingResource(i % 2 == 0 ? folder1 : folder2)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
addedFiles.add(documentHeld);
}
RestRequestQueryModel queryReq = getContentFromSiteQuery(testSite.getId());
SearchRequest searchRequest = new SearchRequest();
searchRequest.setQuery(queryReq);
STEP("Wait until all files are searchable.");
await().atMost(30, TimeUnit.SECONDS)
.until(() -> getRestAPIFactory().getSearchAPI(null).search(searchRequest).getPagination()
.getTotalItems() == NUMBER_OF_FILES);
holdBulkOperation = HoldBulkOperation.builder()
.query(queryReq)
.op(HoldBulkOperationType.ADD).build();
}
/**
* Given a user with the add to hold capability and hold filing permission
* When the user adds content from a site to a hold using the bulk API
* Then the content is added to the hold and the status of the bulk operation is DONE
*/
@Test
public void addContentFromTestSiteToHoldUsingBulkAPI()
{
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
UserRole.SiteCollaborator, hold.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
users.add(userAddHoldPermission);
STEP("Add content from the site to the hold using the bulk API.");
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.startBulkProcess(holdBulkOperation, hold.getId());
// Verify the status code
assertStatusCode(ACCEPTED);
assertEquals(NUMBER_OF_FILES, bulkOperationEntry.getTotalItems());
STEP("Wait until all files are added to the hold.");
await().atMost(20, TimeUnit.SECONDS).until(
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold.getId()).getEntries().size()
== NUMBER_OF_FILES);
List<String> holdChildrenNodeRefs = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.getChildren(hold.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
HoldChild::getId).toList();
assertEquals(addedFiles.stream().map(FileModel::getNodeRefWithoutVersion).sorted().toList(),
holdChildrenNodeRefs.stream().sorted().toList());
STEP("Check the bulk status.");
HoldBulkStatus holdBulkStatus = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.getBulkStatus(hold.getId(), bulkOperationEntry.getBulkStatusId());
assertBulkProcessStatus(holdBulkStatus, NUMBER_OF_FILES, 0, null, holdBulkOperation);
STEP("Check the bulk statuses.");
HoldBulkStatusCollection holdBulkStatusCollection = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.getBulkStatuses(hold.getId());
assertEquals(Arrays.asList(holdBulkStatus),
holdBulkStatusCollection.getEntries().stream().map(HoldBulkStatusEntry::getEntry).toList());
}
/**
* Given a user with the add to hold capability and hold filing permission
* When the user adds content from a folder and all subfolders to a hold using the bulk API
* Then the content is added to the hold and the status of the bulk operation is DONE
*/
@Test
public void addContentFromFolderAndAllSubfoldersToHoldUsingBulkAPI()
{
hold3 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
holds.add(hold3);
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
UserRole.SiteCollaborator, hold3.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
users.add(userAddHoldPermission);
STEP("Add content from the site to the hold using the bulk API.");
// Get content from folder and all subfolders of the root folder
HoldBulkOperation bulkOperation = HoldBulkOperation.builder()
.query(getContentFromFolderAndAllSubfoldersQuery(rootFolder.getNodeRefWithoutVersion()))
.op(HoldBulkOperationType.ADD).build();
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.startBulkProcess(bulkOperation, hold3.getId());
// Verify the status code
assertStatusCode(ACCEPTED);
assertEquals(NUMBER_OF_FILES, bulkOperationEntry.getTotalItems());
STEP("Wait until all files are added to the hold.");
await().atMost(20, TimeUnit.SECONDS).until(
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold3.getId()).getEntries().size()
== NUMBER_OF_FILES);
List<String> holdChildrenNodeRefs = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.getChildren(hold3.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
HoldChild::getId).toList();
assertEquals(addedFiles.stream().map(FileModel::getNodeRefWithoutVersion).sorted().toList(),
holdChildrenNodeRefs.stream().sorted().toList());
STEP("Check the bulk status.");
HoldBulkStatus holdBulkStatus = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.getBulkStatus(hold3.getId(), bulkOperationEntry.getBulkStatusId());
assertBulkProcessStatus(holdBulkStatus, NUMBER_OF_FILES, 0, null, bulkOperation);
STEP("Check the bulk statuses.");
HoldBulkStatusCollection holdBulkStatusCollection = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.getBulkStatuses(hold3.getId());
assertEquals(List.of(holdBulkStatus),
holdBulkStatusCollection.getEntries().stream().map(HoldBulkStatusEntry::getEntry).toList());
}
/**
* Given a user without the add to hold capability
* When the user adds content from a site to a hold using the bulk API
* Then the user receives access denied error
*/
@Test
public void testBulkProcessWithUserWithoutAddToHoldCapability()
{
UserModel userWithoutAddToHoldCapability = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
UserRole
.SiteCollaborator,
hold.getId(), UserRoles.ROLE_RM_POWER_USER, PERMISSION_FILING);
users.add(userWithoutAddToHoldCapability);
STEP("Add content from the site to the hold using the bulk API.");
getRestAPIFactory().getHoldsAPI(userWithoutAddToHoldCapability)
.startBulkProcess(holdBulkOperation, hold.getId());
STEP("Verify the response status code and the error message.");
assertStatusCode(FORBIDDEN);
getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary(ACCESS_DENIED_ERROR_MESSAGE);
}
/**
* Given a user without the filing permission on a hold
* When the user adds content from a site to a hold using the bulk API
* Then the user receives access denied error
*/
@Test
public void testBulkProcessWithUserWithoutFilingPermissionOnAHold()
{
// User without filing permission on a hold
UserModel userWithoutPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
UserRole.SiteCollaborator, hold.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_READ_RECORDS);
users.add(userWithoutPermission);
STEP("Add content from the site to the hold using the bulk API.");
getRestAPIFactory().getHoldsAPI(userWithoutPermission)
.startBulkProcess(holdBulkOperation, hold.getId());
STEP("Verify the response status code and the error message.");
assertStatusCode(FORBIDDEN);
getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary(ACCESS_DENIED_ERROR_MESSAGE);
}
/**
* Given a user without the write permission on all the content
* When the user adds content from a site to a hold using the bulk API
* Then all processed items are marked as errors and the last error message contains access denied error
*/
@Test
public void testBulkProcessWithUserWithoutWritePermissionOnTheContent()
{
// User without write permission on the content
UserModel userWithoutPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(
testSite, UserRole.SiteConsumer,
hold.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
users.add(userWithoutPermission);
// Wait until permissions are reverted
SearchRequest searchRequest = new SearchRequest();
searchRequest.setQuery(holdBulkOperation.getQuery());
await().atMost(30, TimeUnit.SECONDS)
.until(() -> getRestAPIFactory().getSearchAPI(userWithoutPermission).search(searchRequest).getPagination()
.getTotalItems() == NUMBER_OF_FILES);
STEP("Add content from the site to the hold using the bulk API.");
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(
userWithoutPermission).startBulkProcess(holdBulkOperation, hold.getId());
STEP("Verify the response.");
assertStatusCode(ACCEPTED);
await().atMost(20, TimeUnit.SECONDS).until(() ->
Objects.equals(getRestAPIFactory().getHoldsAPI(userWithoutPermission)
.getBulkStatus(hold.getId(), bulkOperationEntry.getBulkStatusId()).getStatus(), "DONE"));
HoldBulkStatus holdBulkStatus = getRestAPIFactory().getHoldsAPI(userWithoutPermission)
.getBulkStatus(hold.getId(), bulkOperationEntry.getBulkStatusId());
assertBulkProcessStatus(holdBulkStatus, NUMBER_OF_FILES, NUMBER_OF_FILES, ACCESS_DENIED_ERROR_MESSAGE,
holdBulkOperation);
}
/**
* Given a user without the write permission on one file
* When the user adds content from a site to a hold using the bulk API
* Then all processed items are added to the hold except the one that the user does not have write permission
* And the status of the bulk operation is DONE, contains the error message and the number of errors is 1
*/
@Test
public void testBulkProcessWithUserWithoutWritePermissionOnOneFile()
{
hold2 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
holds.add(hold2);
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
UserRole.SiteCollaborator, hold2.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
users.add(userAddHoldPermission);
contentActions.setPermissionForUser(getAdminUser().getUsername(), getAdminUser().getPassword(),
testSite.getId(), addedFiles.get(0).getName(), userAddHoldPermission.getUsername(),
UserRole.SiteConsumer.getRoleId(), false);
STEP("Add content from the site to the hold using the bulk API.");
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.startBulkProcess(holdBulkOperation, hold2.getId());
// Verify the status code
assertStatusCode(ACCEPTED);
assertEquals(NUMBER_OF_FILES, bulkOperationEntry.getTotalItems());
STEP("Wait until all files are added to the hold.");
await().atMost(30, TimeUnit.SECONDS).until(
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold2.getId()).getEntries().size()
== NUMBER_OF_FILES - 1);
await().atMost(30, TimeUnit.SECONDS).until(
() -> getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.getBulkStatus(hold2.getId(), bulkOperationEntry.getBulkStatusId()).getProcessedItems()
== NUMBER_OF_FILES);
List<String> holdChildrenNodeRefs = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.getChildren(hold2.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
HoldChild::getId).toList();
assertEquals(addedFiles.stream().skip(1).map(FileModel::getNodeRefWithoutVersion).sorted().toList(),
holdChildrenNodeRefs.stream().sorted().toList());
STEP("Check the bulk status.");
HoldBulkStatus holdBulkStatus = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.getBulkStatus(hold2.getId(), bulkOperationEntry.getBulkStatusId());
assertBulkProcessStatus(holdBulkStatus, NUMBER_OF_FILES, 1, ACCESS_DENIED_ERROR_MESSAGE, holdBulkOperation);
STEP("Check the bulk statuses.");
HoldBulkStatusCollection holdBulkStatusCollection = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.getBulkStatuses(hold2.getId());
assertEquals(List.of(holdBulkStatus),
holdBulkStatusCollection.getEntries().stream().map(HoldBulkStatusEntry::getEntry).toList());
// Revert the permissions
contentActions.setPermissionForUser(getAdminUser().getUsername(), getAdminUser().getPassword(),
testSite.getId(), addedFiles.get(0).getName(), userAddHoldPermission.getUsername(),
UserRole.SiteCollaborator.getRoleId(), true);
}
/**
* Given an unauthenticated user
* When the user adds content from a site to a hold using the bulk API
* Then the user receives unauthorized error
*/
@Test
public void testBulkProcessAsUnauthenticatedUser()
{
STEP("Start bulk process as unauthenticated user");
getRestAPIFactory().getHoldsAPI(new UserModel(getAdminUser().getUsername(), "wrongPassword"))
.startBulkProcess(holdBulkOperation, hold.getId());
STEP("Verify the response status code.");
assertStatusCode(UNAUTHORIZED);
}
/**
* Given a user with the add to hold capability and hold filing permission
* When the user adds content from a site to a hold using the bulk API
* And the hold does not exist
* Then the user receives not found error
*/
@Test
public void testBulkProcessForNonExistentHold()
{
STEP("Start bulk process for non existent hold");
getRestAPIFactory().getHoldsAPI(getAdminUser()).startBulkProcess(holdBulkOperation, "nonExistentHoldId");
STEP("Verify the response status code.");
assertStatusCode(NOT_FOUND);
}
/**
* Given a user with the add to hold capability and hold filing permission
* When the user adds content from a site to a hold using the bulk API
* and the bulk operation is invalid
* Then the user receives bad request error
*/
@Test
public void testGetBulkStatusesForInvalidOperation()
{
STEP("Start bulk process for non existent hold");
HoldBulkOperation invalidHoldBulkOperation = HoldBulkOperation.builder().op(null)
.query(holdBulkOperation.getQuery()).build();
getRestAPIFactory().getHoldsAPI(getAdminUser()).startBulkProcess(invalidHoldBulkOperation, hold.getId());
STEP("Verify the response status code.");
assertStatusCode(BAD_REQUEST);
}
/**
* Given a user with the add to hold capability and hold filing permission
* When the user adds content from a site to a hold using the bulk API
* And the hold does not exist
* Then the user receives not found error
*/
@Test
public void testGetBulkStatusForNonExistentHold()
{
STEP("Start bulk process for non existent hold");
getRestAPIFactory().getHoldsAPI(getAdminUser()).getBulkStatus("nonExistentHoldId", "nonExistenBulkStatusId");
STEP("Verify the response status code.");
assertStatusCode(NOT_FOUND);
}
/**
* Given a user with the add to hold capability and hold filing permission
* When the user adds content from a site to a hold using the bulk API
* And the bulk status does not exist
* Then the user receives not found error
*/
@Test
public void testGetBulkStatusForNonExistentBulkStatus()
{
STEP("Start bulk process for non bulk status");
getRestAPIFactory().getHoldsAPI(getAdminUser()).getBulkStatus(hold.getId(), "nonExistenBulkStatusId");
STEP("Verify the response status code.");
assertStatusCode(NOT_FOUND);
}
/**
* Given a user with the add to hold capability and hold filing permission
* When the user adds content from a site to a hold using the bulk API
* And the hold does not exist
* Then the user receives not found error
*/
@Test
public void testGetBulkStatusesForNonExistentHold()
{
STEP("Start bulk process for non existent hold");
getRestAPIFactory().getHoldsAPI(getAdminUser()).getBulkStatuses("nonExistentHoldId");
STEP("Verify the response status code.");
assertStatusCode(NOT_FOUND);
}
/**
* Given a user with the add to hold capability and hold filing permission
* When the user adds content from all sites to a hold using the bulk API to exceed the limit (30 items)
* Then the user receives bad request error
*/
@Test
public void testExceedingBulkOperationLimit()
{
RestRequestQueryModel queryReq = new RestRequestQueryModel();
queryReq.setQuery("TYPE:content");
queryReq.setLanguage("afts");
HoldBulkOperation exceedLimitOp = HoldBulkOperation.builder()
.query(queryReq)
.op(HoldBulkOperationType.ADD).build();
STEP("Start bulk process to exceed the limit");
getRestAPIFactory().getHoldsAPI(getAdminUser()).startBulkProcess(exceedLimitOp, hold.getId());
STEP("Verify the response status code.");
assertStatusCode(BAD_REQUEST);
}
/**
* Given a user with the add to hold capability and hold filing permission
* When the user adds content from a site to a hold using the bulk API
* And then the user cancels the bulk operation
* Then the user receives OK status code
*/
@Test
public void testBulkProcessCancellationWithAllowedUser()
{
Hold hold4 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
holds.add(hold4);
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
UserRole.SiteCollaborator, hold4.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
users.add(userAddHoldPermission);
STEP("Add content from the site to the hold using the bulk API.");
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.startBulkProcess(holdBulkOperation, hold4.getId());
// Verify the status code
assertStatusCode(ACCEPTED);
assertEquals(NUMBER_OF_FILES, bulkOperationEntry.getTotalItems());
STEP("Cancel the bulk operation.");
getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.cancelBulkOperation(hold4.getId(), bulkOperationEntry.getBulkStatusId(), new BulkBodyCancel());
// Verify the status code
assertStatusCode(OK);
}
/**
* Given a user with the add to hold capability and hold filing permission
* When the user adds content from a site to a hold using the bulk API
* And a 2nd user without the add to hold capability cancels the bulk operation
* Then the 2nd user receives access denied error
*/
@Test
public void testBulkProcessCancellationWithUserWithoutAddToHoldCapability()
{
Hold hold5 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
holds.add(hold5);
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
UserRole.SiteCollaborator, hold5.getId(), UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
users.add(userAddHoldPermission);
STEP("Add content from the site to the hold using the bulk API.");
HoldBulkOperationEntry bulkOperationEntry = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.startBulkProcess(holdBulkOperation, hold5.getId());
// Verify the status code
assertStatusCode(ACCEPTED);
assertEquals(NUMBER_OF_FILES, bulkOperationEntry.getTotalItems());
UserModel userWithoutAddToHoldCapability = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
UserRole
.SiteCollaborator,
hold5.getId(), UserRoles.ROLE_RM_POWER_USER, PERMISSION_FILING);
users.add(userWithoutAddToHoldCapability);
STEP("Cancel the bulk operation.");
getRestAPIFactory().getHoldsAPI(userWithoutAddToHoldCapability)
.cancelBulkOperation(hold5.getId(), bulkOperationEntry.getBulkStatusId(), new BulkBodyCancel());
STEP("Verify the response status code and the error message.");
assertStatusCode(FORBIDDEN);
getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary(ACCESS_DENIED_ERROR_MESSAGE);
}
private void assertBulkProcessStatus(HoldBulkStatus holdBulkStatus, long expectedProcessedItems,
int expectedErrorsCount, String expectedErrorMessage, HoldBulkOperation holdBulkOperation)
{
assertEquals("DONE", holdBulkStatus.getStatus());
assertEquals(expectedProcessedItems, holdBulkStatus.getTotalItems());
assertEquals(expectedProcessedItems, holdBulkStatus.getProcessedItems());
assertEquals(expectedErrorsCount, holdBulkStatus.getErrorsCount());
assertEquals(holdBulkStatus.getHoldBulkOperation(), holdBulkOperation);
assertNotNull(holdBulkStatus.getStartTime());
assertNotNull(holdBulkStatus.getEndTime());
if (expectedErrorMessage != null)
{
assertTrue(holdBulkStatus.getLastError().contains(expectedErrorMessage));
}
}
private RestRequestQueryModel getContentFromSiteQuery(String siteId)
{
RestRequestQueryModel queryReq = new RestRequestQueryModel();
queryReq.setQuery("SITE:\"" + siteId + "\" and TYPE:content");
queryReq.setLanguage("afts");
return queryReq;
}
private RestRequestQueryModel getContentFromFolderAndAllSubfoldersQuery(String folderId)
{
RestRequestQueryModel queryReq = new RestRequestQueryModel();
queryReq.setQuery("ANCESTOR:\"workspace://SpacesStore/" + folderId + "\" and TYPE:content");
queryReq.setLanguage("afts");
return queryReq;
}
@AfterClass(alwaysRun = true)
public void cleanupAddToHoldsBulkV1Tests()
{
dataSite.usingAdmin().deleteSite(testSite);
users.forEach(user -> getDataUser().usingAdmin().deleteUser(user));
holds.forEach(hold -> getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(hold.getId()));
}
}

View File

@@ -60,7 +60,7 @@ import org.alfresco.dataprep.CMISUtil;
import org.alfresco.dataprep.ContentActions;
import org.alfresco.rest.model.RestNodeModel;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.hold.HoldEntry;
import org.alfresco.rest.rm.community.model.hold.v0.HoldEntry;
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;

View File

@@ -0,0 +1,386 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.hold;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.TRANSFERS_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.UNFILED_RECORDS_CONTAINER_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAspects.FROZEN_ASPECT;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentType.UNFILED_RECORD_FOLDER_TYPE;
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_MANAGER;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.rest.rm.community.utils.CoreUtil.toContentModel;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.IMAGE_FILE;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createElectronicRecordModel;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createNonElectronicRecordModel;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.getFile;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.apache.commons.httpclient.HttpStatus.SC_BAD_REQUEST;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import static org.testng.AssertJUnit.assertFalse;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.dataprep.ContentActions;
import org.alfresco.rest.model.RestNodeAssociationModelCollection;
import org.alfresco.rest.model.RestNodeModel;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldChild;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* V1 API tests for adding content/record folder/records to holds
*
* @author Damian Ujma
*/
public class AddToHoldsV1Tests extends BaseRMRestTest
{
private static final String ACCESS_DENIED_ERROR_MESSAGE = "Access Denied. You do not have the appropriate " +
"permissions to perform this operation.";
private static final String INVALID_TYPE_ERROR_MESSAGE = "Only records, record folders or content can be added to a hold.";
private static final String LOCKED_FILE_ERROR_MESSAGE = "Locked content can't be added to a hold.";
private static final String HOLD = "HOLD" + generateTestPrefix(AddToHoldsV1Tests.class);
private String holdNodeRef;
private SiteModel testSite;
private FileModel documentHeld;
private FileModel contentToAddToHold;
private FileModel contentAddToHoldNoPermission;
private Hold hold;
private UserModel userAddHoldPermission;
private final List<UserModel> users = new ArrayList<>();
private final List<String> nodesToBeClean = new ArrayList<>();
@Autowired
private RoleService roleService;
@Autowired
private ContentActions contentActions;
@BeforeClass(alwaysRun = true)
public void preconditionForAddContentToHold()
{
STEP("Create a hold.");
hold = createHold(FILE_PLAN_ALIAS,
Hold.builder().name(HOLD).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), getAdminUser());
holdNodeRef = hold.getId();
STEP("Create test files.");
testSite = dataSite.usingAdmin().createPublicRandomSite();
documentHeld = dataContent.usingAdmin().usingSite(testSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
contentToAddToHold = dataContent.usingAdmin().usingSite(testSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
contentAddToHoldNoPermission = dataContent.usingAdmin().usingSite(testSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
STEP("Add the content to the hold.");
getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(documentHeld.getNodeRefWithoutVersion()).build(), hold.getId());
STEP("Create users");
userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
UserRole.SiteCollaborator, holdNodeRef, UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING);
users.add(userAddHoldPermission);
}
/**
* Given a hold that contains at least one active content
* When I use the existing REST API to retrieve the contents of the hold
* Then I should see all the active content on hold
*/
@Test
public void retrieveTheContentOfTheHoldUsingV1API()
{
STEP("Retrieve the list of children from the hold and collect the entries that have the name of the active " +
"content held");
List<String> documentNames = restClient.authenticateUser(getAdminUser()).withCoreAPI()
.usingNode(toContentModel(holdNodeRef))
.listChildren().getEntries().stream()
.map(RestNodeModel::onModel)
.map(RestNodeModel::getName)
.filter(documentName -> documentName.equals(documentHeld.getName()))
.toList();
STEP("Check the list of active content");
assertEquals(documentNames, Set.of(documentHeld.getName()));
}
/**
* Given a hold that contains at least one active content
* When I use the existing REST API to retrieve the holds the content is added
* Then the hold where the content held is returned
*/
@Test
public void retrieveTheHoldWhereTheContentIsAdded()
{
RestNodeAssociationModelCollection holdsEntries = getRestAPIFactory()
.getNodeAPI(documentHeld).usingParams("where=(assocType='rma:frozenContent')").getParents();
Hold retrievedHold = getRestAPIFactory().getHoldsAPI(getAdminUser())
.getHold(holdsEntries.getEntries().get(0).getModel().getId());
assertEquals(retrievedHold, hold, "Holds are not equal");
}
/**
* Valid nodes to be added to hold
*/
@DataProvider(name = "validNodesForAddToHold")
public Object[][] getValidNodesForAddToHold()
{
//create electronic and nonElectronic record in record folder
RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI();
nodesToBeClean.add(recordFolder.getParentId());
Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolder.getId(),
getFile
(IMAGE_FILE));
assertStatusCode(CREATED);
Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(),
recordFolder.getId());
assertStatusCode(CREATED);
getRestAPIFactory().getRMUserAPI().addUserPermission(recordFolder.getId(), userAddHoldPermission,
PERMISSION_FILING);
RecordCategoryChild folderToHold = createCategoryFolderInFilePlan();
getRestAPIFactory().getRMUserAPI().addUserPermission(folderToHold.getId(), userAddHoldPermission,
PERMISSION_FILING);
nodesToBeClean.add(folderToHold.getParentId());
return new String[][]
{ // record folder
{ folderToHold.getId() },
//electronic record
{ electronicRecord.getId() },
// non electronic record
{ nonElectronicRecord.getId() },
// document from collaboration site
{ contentToAddToHold.getNodeRefWithoutVersion() },
};
}
/**
* Given record folder/record/document not on hold
* And a hold
* And file permission on the hold
* And the appropriate capability to add to hold
* When I use the existing REST API to add the node to the hold
* Then the record folder/record/document is added to the hold
* And the item is frozen
*
* @throws Exception
*/
@Test(dataProvider = "validNodesForAddToHold")
public void addValidNodesToHoldWithAllowedUser(String nodeId) throws Exception
{
STEP("Add node to hold with user with permission.");
getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
.addChildToHold(HoldChild.builder().id(nodeId).build(), hold.getId());
STEP("Check the node is frozen.");
assertTrue(hasAspect(nodeId, FROZEN_ASPECT));
}
/**
* Data provider with user without correct permission to add to hold and the node ref to be added to hold
*
* @return object with user model and the node ref to be added to hold
*/
@DataProvider(name = "userWithoutPermissionForAddToHold")
public Object[][] getUserWithoutPermissionForAddToHold()
{
//create record folder
RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
//create a rm manager and grant read permission over the record folder created
UserModel user = roleService.createUserWithRMRoleAndRMNodePermission(ROLE_RM_MANAGER.roleId,
recordFolder.getId(),
PERMISSION_READ_RECORDS);
getRestAPIFactory().getRMUserAPI().addUserPermission(holdNodeRef, user, PERMISSION_FILING);
nodesToBeClean.add(recordFolder.getParentId());
return new Object[][]
{ // user without write permission on the content
{
roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole.SiteConsumer,
holdNodeRef, UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING),
contentAddToHoldNoPermission.getNodeRefWithoutVersion()
},
// user with write permission on the content and without filling permission on a hold
{
roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole
.SiteCollaborator,
holdNodeRef, UserRoles.ROLE_RM_MANAGER, PERMISSION_READ_RECORDS),
contentAddToHoldNoPermission.getNodeRefWithoutVersion()
},
// user with write permission on the content, filling permission on a hold without add to
// hold capability
{
roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole
.SiteCollaborator,
holdNodeRef, UserRoles.ROLE_RM_POWER_USER, PERMISSION_READ_RECORDS),
contentAddToHoldNoPermission.getNodeRefWithoutVersion()
},
//user without write permission on RM record folder
{
user, recordFolder.getId()
},
};
}
/**
* Given a node not on hold
* And a hold
* And user without right permission to add to hold
* When I use the existing REST API to add the node to the hold
* Then the node is not added to the hold
* And the node is not frozen
*
* @throws Exception
*/
@Test(dataProvider = "userWithoutPermissionForAddToHold")
public void addContentToHoldWithUserWithoutHoldPermission(UserModel userModel, String nodeToBeAddedToHold)
throws Exception
{
users.add(userModel);
STEP("Add the node to the hold with user without permission.");
getRestAPIFactory()
.getHoldsAPI(userModel)
.addChildToHold(HoldChild.builder().id(nodeToBeAddedToHold).build(), holdNodeRef);
assertStatusCode(FORBIDDEN);
getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary(ACCESS_DENIED_ERROR_MESSAGE);
STEP("Check the node is not frozen.");
assertFalse(hasAspect(nodeToBeAddedToHold, FROZEN_ASPECT));
}
/**
* Data provider with invalid node types that can be added to a hold
*/
@DataProvider(name = "invalidNodesForAddToHold")
public Object[][] getInvalidNodesForAddToHold()
{
//create locked file
FileModel contentLocked = dataContent.usingAdmin().usingSite(testSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
contentActions.checkOut(getAdminUser().getUsername(), getAdminUser().getPassword(),
testSite.getId(), contentLocked.getName());
RecordCategory category = createRootCategory(getRandomAlphanumeric());
nodesToBeClean.add(category.getId());
return new Object[][]
{ // file plan node id
{ getFilePlan(FILE_PLAN_ALIAS).getId(), SC_BAD_REQUEST, INVALID_TYPE_ERROR_MESSAGE },
//transfer container
{ getTransferContainer(TRANSFERS_ALIAS).getId(), SC_BAD_REQUEST, INVALID_TYPE_ERROR_MESSAGE },
// a record category
{ category.getId(), SC_BAD_REQUEST, INVALID_TYPE_ERROR_MESSAGE },
// unfiled records root
{ getUnfiledContainer(UNFILED_RECORDS_CONTAINER_ALIAS).getId(), SC_BAD_REQUEST,
INVALID_TYPE_ERROR_MESSAGE },
// an arbitrary unfiled records folder
{ createUnfiledContainerChild(UNFILED_RECORDS_CONTAINER_ALIAS, "Unfiled Folder " +
getRandomAlphanumeric(), UNFILED_RECORD_FOLDER_TYPE).getId(), SC_BAD_REQUEST,
INVALID_TYPE_ERROR_MESSAGE },
//folder,
{ dataContent.usingAdmin().usingSite(testSite).createFolder().getNodeRef(), SC_BAD_REQUEST,
INVALID_TYPE_ERROR_MESSAGE },
//document locked
{ contentLocked.getNodeRefWithoutVersion(), SC_BAD_REQUEST, LOCKED_FILE_ERROR_MESSAGE }
};
}
/**
* Given a node that is not a document/record/ record folder ( a valid node type to be added to hold)
* And a hold
* And user without right permission to add to hold
* When I use the existing REST API to add the node to the hold
* Then the node is not added to the hold
* And the node is not frozen
*
* @throws Exception
*/
@Test(dataProvider = "invalidNodesForAddToHold")
public void addInvalidNodesToHold(String itemNodeRef, int responseCode, String errorMessage) throws Exception
{
STEP("Add the node to the hold ");
getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(itemNodeRef).build(), holdNodeRef);
assertStatusCode(HttpStatus.valueOf(responseCode));
getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary(errorMessage);
STEP("Check node is not frozen.");
assertFalse(hasAspect(itemNodeRef, FROZEN_ASPECT));
}
private Hold createHold(String parentId, Hold hold, UserModel user)
{
FilePlanAPI filePlanAPI = getRestAPIFactory().getFilePlansAPI(user);
return filePlanAPI.createHold(hold, parentId);
}
@AfterClass(alwaysRun = true)
public void cleanUpAddContentToHold()
{
getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(holdNodeRef);
dataSite.usingAdmin().deleteSite(testSite);
users.forEach(user -> getDataUser().usingAdmin().deleteUser(user));
nodesToBeClean.forEach(this::deleteRecordCategory);
}
}

View File

@@ -0,0 +1,186 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.hold;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
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.ArrayList;
import java.util.List;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldDeletionReason;
import org.testng.annotations.AfterClass;
import org.testng.annotations.Test;
/**
* This class contains the tests for the Holds CRUD V1 API
*
* @author Damian Ujma
*/
public class HoldsTests extends BaseRMRestTest
{
private final List<String> nodeRefs = new ArrayList<>();
@Test
public void testGetHold()
{
String holdName = "Hold" + getRandomAlphanumeric();
String holdDescription = "Description" + getRandomAlphanumeric();
String holdReason = "Reason" + getRandomAlphanumeric();
// Create the hold
Hold hold = Hold.builder()
.name(holdName)
.description(holdDescription)
.reason(holdReason)
.build();
Hold createdHold = getRestAPIFactory().getFilePlansAPI()
.createHold(hold, FILE_PLAN_ALIAS);
// Get the hold
Hold receivedHold = getRestAPIFactory().getHoldsAPI().getHold(createdHold.getId());
nodeRefs.add(receivedHold.getId());
// Verify the status code
assertStatusCode(OK);
assertEquals(receivedHold.getName(), holdName);
assertEquals(receivedHold.getDescription(), holdDescription);
assertEquals(receivedHold.getReason(), holdReason);
assertNotNull(receivedHold.getId());
}
@Test
public void testUpdateHold()
{
String holdName = "Hold" + getRandomAlphanumeric();
String holdDescription = "Description" + getRandomAlphanumeric();
String holdReason = "Reason" + getRandomAlphanumeric();
// Create the hold
Hold hold = Hold.builder()
.name(holdName)
.description(holdDescription)
.reason(holdReason)
.build();
Hold createdHold = getRestAPIFactory().getFilePlansAPI()
.createHold(hold, FILE_PLAN_ALIAS);
nodeRefs.add(createdHold.getId());
Hold holdModel = Hold.builder()
.name("Updated" + holdName)
.description("Updated" + holdDescription)
.reason("Updated" + holdReason)
.build();
// Update the hold
Hold updatedHold = getRestAPIFactory().getHoldsAPI().updateHold(holdModel, createdHold.getId());
// Verify the status code
assertStatusCode(OK);
assertEquals(updatedHold.getName(), "Updated" + holdName);
assertEquals(updatedHold.getDescription(), "Updated" + holdDescription);
assertEquals(updatedHold.getReason(), "Updated" + holdReason);
assertNotNull(updatedHold.getId());
}
@Test
public void testDeleteHold()
{
String holdName = "Hold" + getRandomAlphanumeric();
String holdDescription = "Description" + getRandomAlphanumeric();
String holdReason = "Reason" + getRandomAlphanumeric();
// Create the hold
Hold hold = Hold.builder()
.name(holdName)
.description(holdDescription)
.reason(holdReason)
.build();
Hold createdHold = getRestAPIFactory().getFilePlansAPI()
.createHold(hold, FILE_PLAN_ALIAS);
nodeRefs.add(createdHold.getId());
// Delete the hold
getRestAPIFactory().getHoldsAPI().deleteHold(createdHold.getId());
// Verify the status code
assertStatusCode(NO_CONTENT);
// Try to get the hold
getRestAPIFactory().getHoldsAPI().getHold(createdHold.getId());
// Verify the status code
assertStatusCode(NOT_FOUND);
}
@Test
public void testDeleteHoldWithReason()
{
String holdName = "Hold" + getRandomAlphanumeric();
String holdDescription = "Description" + getRandomAlphanumeric();
String holdReason = "Reason" + getRandomAlphanumeric();
// Create the hold
Hold hold = Hold.builder()
.name(holdName)
.description(holdDescription)
.reason(holdReason)
.build();
Hold createdHold = getRestAPIFactory().getFilePlansAPI()
.createHold(hold, FILE_PLAN_ALIAS);
nodeRefs.add(createdHold.getId());
// Delete the hold with the reason
getRestAPIFactory().getHoldsAPI()
.deleteHoldWithReason(HoldDeletionReason.builder().reason("Example reason").build(), createdHold.getId());
// Verify the status code
assertStatusCode(OK);
// Try to get the hold
getRestAPIFactory().getHoldsAPI().getHold(createdHold.getId());
// Verify the status code
assertStatusCode(NOT_FOUND);
}
@AfterClass(alwaysRun = true)
public void cleanUpHoldsTests()
{
nodeRefs.forEach(nodeRef -> getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(nodeRef));
}
}

View File

@@ -0,0 +1,337 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.hold;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAspects.ASPECTS_VITAL_RECORD;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAspects.ASPECTS_VITAL_RECORD_DEFINITION;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.rest.rm.community.utils.CoreUtil.createBodyForMoveCopy;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.apache.commons.httpclient.HttpStatus.SC_INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.OK;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import static org.testng.AssertJUnit.assertFalse;
import java.io.File;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.core.JsonBodyGenerator;
import org.alfresco.rest.core.v0.BaseAPI.RM_ACTIONS;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.common.ReviewPeriod;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldChild;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolder;
import org.alfresco.rest.rm.community.model.recordfolder.RecordFolderProperties;
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.rest.v0.service.DispositionScheduleService;
import org.alfresco.utility.Utility;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
* V1 API tests to check actions on frozen content
*
* @author Damian Ujma
*/
public class PreventActionsOnFrozenContentV1Tests extends BaseRMRestTest
{
private static String holdNodeRef;
private static FileModel contentHeld;
private static File updatedFile;
private static FolderModel folderModel;
private static RecordCategoryChild recordFolder;
private static Record recordFrozen;
private static Record recordNotHeld;
private static RecordCategory categoryWithRS;
private Hold hold;
@Autowired
private DispositionScheduleService dispositionScheduleService;
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@BeforeClass(alwaysRun = true)
public void preconditionForPreventActionsOnFrozenContent()
{
String holdOne = "HOLD" + generateTestPrefix(PreventActionsOnFrozenContentV1Tests.class);
STEP("Create a hold.");
hold = createHold(FILE_PLAN_ALIAS,
Hold.builder().name(holdOne).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(), getAdminUser());
holdNodeRef = hold.getId();
STEP("Create a test file.");
testSite = dataSite.usingAdmin().createPublicRandomSite();
contentHeld = dataContent.usingAdmin().usingSite(testSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
STEP("Add the file to the hold.");
getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(contentHeld.getNodeRefWithoutVersion()).build(), hold.getId());
STEP("Get a file resource.");
updatedFile = Utility.getResourceTestDataFile("SampleTextFile_10kb.txt");
STEP("Create a folder withing the test site .");
folderModel = dataContent.usingAdmin().usingSite(testSite)
.createFolder();
STEP("Create a record folder with some records");
recordFolder = createCategoryFolderInFilePlan();
recordFrozen = createElectronicRecord(recordFolder.getId(), getRandomName("elRecordFrozen"));
recordNotHeld = createElectronicRecord(recordFolder.getId(), getRandomName("elRecordNotHeld"));
assertStatusCode(CREATED);
STEP("Add the record to the hold.");
getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(recordFrozen.getId()).build(), hold.getId());
}
/**
* Given active content on hold
* When I try to edit the properties
* Or perform an action that edits the properties
* Then I am not successful
*/
@Test
public void editPropertiesForContentHeld() throws Exception
{
STEP("Update name property of the held content");
JsonObject nameUpdated = Json.createObjectBuilder().add("name", "HeldNameUpdated").build();
restClient.authenticateUser(getAdminUser()).withCoreAPI().usingNode(contentHeld)
.updateNode(nameUpdated.toString());
STEP("Check the request failed.");
restClient.assertStatusCodeIs(FORBIDDEN);
restClient.assertLastError().containsSummary("Frozen content can't be updated.");
}
/*
* Given active content on hold
* When I try to update the content
* Then I am not successful
*/
@Test
public void updateContentForFrozenFile() throws Exception
{
STEP("Update content of the held file");
restClient.authenticateUser(getAdminUser()).withCoreAPI().usingNode(contentHeld).updateNodeContent(updatedFile);
STEP("Check the request failed.");
restClient.assertStatusCodeIs(INTERNAL_SERVER_ERROR);
restClient.assertLastError().containsSummary("Frozen content can't be updated.");
}
/*
* Given active content on hold
* When I try to delete the content
* Then I am not successful
*/
@Test
public void deleteFrozenFile() throws Exception
{
STEP("Delete frozen file");
restClient.authenticateUser(getAdminUser()).withCoreAPI().usingNode(contentHeld)
.deleteNode(contentHeld.getNodeRefWithoutVersion());
STEP("Check the request failed.");
restClient.assertStatusCodeIs(FORBIDDEN);
restClient.assertLastError().containsSummary("Frozen content can't be deleted.");
}
/**
* Given active content on hold
* When I try to copy the content
* Then I am not successful
*/
@Test
public void copyFrozenFile()
{
STEP("Copy frozen file");
String postBody = JsonBodyGenerator.keyValueJson("targetParentId", folderModel.getNodeRef());
getRestAPIFactory().getNodeAPI(contentHeld).copyNode(postBody);
STEP("Check the request failed.");
assertStatusCode(FORBIDDEN);
getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary("Permission was denied");
}
/**
* Given active content on hold
* When I try to move the content
* Then I am not successful
*/
@Test
public void moveFrozenFile() throws Exception
{
STEP("Move frozen file");
getRestAPIFactory().getNodeAPI(contentHeld).move(createBodyForMoveCopy(folderModel.getNodeRef()));
STEP("Check the request failed.");
assertStatusCode(FORBIDDEN);
getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary("Frozen content can't be moved.");
}
/**
* Given a record folder with a frozen record and another record not held
* When I update the record folder and make the records as vital
* Then I am successful and the records not held are marked as vital
* And the frozen nodes have the vital record search properties updated
*/
@Test
public void updateRecordFolderVitalProperties()
{
STEP("Update the vital record properties for the record folder");
// Create the record folder properties to update
RecordFolder recordFolderToUpdate = RecordFolder.builder()
.properties(RecordFolderProperties.builder()
.vitalRecordIndicator(true)
.reviewPeriod(new ReviewPeriod("month", "1"))
.build())
.build();
// Update the record folder
RecordFolder updatedRecordFolder = getRestAPIFactory().getRecordFolderAPI().updateRecordFolder
(recordFolderToUpdate,
recordFolder.getId());
assertStatusCode(OK);
assertTrue(updatedRecordFolder.getAspectNames().contains(ASPECTS_VITAL_RECORD_DEFINITION));
STEP("Check the frozen record was not marked as vital");
recordFrozen = getRestAPIFactory().getRecordsAPI().getRecord(recordFrozen.getId());
assertFalse(recordFrozen.getAspectNames().contains(ASPECTS_VITAL_RECORD));
assertTrue(recordFrozen.getProperties().getRecordSearchVitalRecordReviewPeriod().contains("month"));
assertTrue(recordFrozen.getProperties().getRecordSearchVitalRecordReviewPeriodExpression().contains("1"));
STEP("Check the record not held was marked as vital");
recordNotHeld = getRestAPIFactory().getRecordsAPI().getRecord(recordNotHeld.getId());
assertTrue(recordNotHeld.getAspectNames().contains(ASPECTS_VITAL_RECORD));
assertNotNull(recordNotHeld.getProperties().getReviewAsOf());
assertTrue(recordNotHeld.getProperties().getRecordSearchVitalRecordReviewPeriod().contains("month"));
assertTrue(recordNotHeld.getProperties().getRecordSearchVitalRecordReviewPeriodExpression().contains("1"));
}
/**
* Given a record folder with a frozen record and another record not held
* When I add a disposition schedule
* Then I am successful
* And the record search disposition schedule properties are updated
*/
@Test
public void createDispositionScheduleOnCategoryWithHeldChildren()
{
STEP("Create a retention schedule on the category with frozen children");
RecordCategory categoryWithRS = getRestAPIFactory().getRecordCategoryAPI()
.getRecordCategory(recordFolder.getParentId());
dispositionScheduleService.createCategoryRetentionSchedule(categoryWithRS.getName(), false);
dispositionScheduleService.addCutOffImmediatelyStep(categoryWithRS.getName());
dispositionScheduleService.addDestroyWithGhostingImmediatelyAfterCutOff(categoryWithRS.getName());
STEP("Check the record folder has a disposition schedule");
RecordFolder folderWithRS = getRestAPIFactory().getRecordFolderAPI().getRecordFolder(recordFolder.getId());
assertNotNull(folderWithRS.getProperties().getRecordSearchDispositionAuthority());
assertNotNull(folderWithRS.getProperties().getRecordSearchDispositionInstructions());
}
/**
* Given a record category with a disposition schedule applied to records
* And the disposition schedule has a retain step immediately and destroy step immediately
* And a complete record added to one hold
* When I execute the retain action
* Then the action is executed
* And the record search disposition schedule properties are updated
*/
@Test
public void retainActionOnFrozenHeldRecords()
{
STEP("Add a category with a disposition schedule.");
categoryWithRS = createRootCategory(getRandomName("CategoryWithRS"));
dispositionScheduleService.createCategoryRetentionSchedule(categoryWithRS.getName(), true);
dispositionScheduleService.addRetainAfterPeriodStep(categoryWithRS.getName(), "immediately");
dispositionScheduleService.addDestroyWithGhostingImmediatelyAfterCutOff(categoryWithRS.getName());
STEP("Create record folder with a record.");
RecordCategoryChild folder = createFolder(categoryWithRS.getId(), getRandomName("RecFolder"));
Record record = createElectronicRecord(folder.getId(), getRandomName("elRecord"));
completeRecord(record.getId());
STEP("Add the record to the hold");
getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(record.getId()).build(), hold.getId());
STEP("Execute the retain action");
rmRolesAndActionsAPI.executeAction(getAdminUser().getUsername(), getAdminUser().getPassword(), record.getName(),
RM_ACTIONS.END_RETENTION, null, SC_INTERNAL_SERVER_ERROR);
STEP("Check the record search disposition properties");
Record recordUpdated = getRestAPIFactory().getRecordsAPI().getRecord(record.getId());
assertTrue(recordUpdated.getProperties().getRecordSearchDispositionActionName()
.contains(RM_ACTIONS.END_RETENTION.getAction()));
assertTrue(recordUpdated.getProperties().getRecordSearchDispositionPeriod().contains("immediately"));
}
private Hold createHold(String parentId, Hold hold, UserModel user)
{
FilePlanAPI filePlanAPI = getRestAPIFactory().getFilePlansAPI(user);
return filePlanAPI.createHold(hold, parentId);
}
@AfterClass(alwaysRun = true)
public void cleanUpPreventActionsOnFrozenContent()
{
getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(holdNodeRef);
dataSite.usingAdmin().deleteSite(testSite);
deleteRecordCategory(recordFolder.getParentId());
deleteRecordCategory(categoryWithRS.getId());
}
}

View File

@@ -52,7 +52,7 @@ import java.util.Set;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.hold.HoldEntry;
import org.alfresco.rest.rm.community.model.hold.v0.HoldEntry;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.user.UserRoles;

View File

@@ -0,0 +1,374 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.hold;
import static java.util.Arrays.asList;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAspects.FROZEN_ASPECT;
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
import static org.alfresco.rest.rm.community.model.user.UserRoles.ROLE_RM_MANAGER;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.IMAGE_FILE;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createElectronicRecordModel;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.createNonElectronicRecordModel;
import static org.alfresco.rest.rm.community.utils.FilePlanComponentsUtil.getFile;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.model.RestNodeAssociationModelCollection;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.hold.Hold;
import org.alfresco.rest.rm.community.model.hold.HoldChild;
import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategoryChild;
import org.alfresco.rest.rm.community.model.user.UserRoles;
import org.alfresco.rest.rm.community.requests.gscore.api.FilePlanAPI;
import org.alfresco.rest.rm.community.requests.gscore.api.RecordFolderAPI;
import org.alfresco.rest.rm.community.utils.CoreUtil;
import org.alfresco.rest.v0.service.RoleService;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* V1 API tests for removing content/record folder/record from holds
*
* @author Damian Ujma
*/
public class RemoveFromHoldsV1Tests extends BaseRMRestTest
{
private static final String HOLD_ONE = "HOLD_ONE" + generateTestPrefix(RemoveFromHoldsV1Tests.class);
private static final String HOLD_TWO = "HOLD_TWO" + generateTestPrefix(RemoveFromHoldsV1Tests.class);
private static final String ACCESS_DENIED_ERROR_MESSAGE = "Access Denied. You do not have the appropriate " +
"permissions to perform this operation.";
private SiteModel testSite;
private SiteModel privateSite;
private String holdNodeRefOne;
private FileModel contentHeld;
private FileModel contentAddToManyHolds;
private List<String> holdsListRef = new ArrayList<>();
private final Set<UserModel> usersToBeClean = new HashSet<>();
private final Set<String> nodesToBeClean = new HashSet<>();
@Autowired
private RoleService roleService;
@BeforeClass(alwaysRun = true)
public void preconditionForRemoveContentFromHold()
{
STEP("Create two holds.");
holdNodeRefOne = createHold(FILE_PLAN_ALIAS,
Hold.builder().name(HOLD_ONE).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(),
getAdminUser()).getId();
String holdNodeRefTwo = createHold(FILE_PLAN_ALIAS,
Hold.builder().name(HOLD_TWO).description(HOLD_DESCRIPTION).reason(HOLD_REASON).build(),
getAdminUser()).getId();
holdsListRef = asList(holdNodeRefOne, holdNodeRefTwo);
STEP("Create test files.");
testSite = dataSite.usingAdmin().createPublicRandomSite();
privateSite = dataSite.usingAdmin().createPrivateRandomSite();
contentHeld = dataContent.usingAdmin().usingSite(testSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
contentAddToManyHolds = dataContent.usingSite(testSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
STEP("Add content to the holds.");
getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(contentHeld.getNodeRefWithoutVersion()).build(), holdNodeRefOne);
getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(contentAddToManyHolds.getNodeRefWithoutVersion()).build(),
holdNodeRefOne);
getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(contentAddToManyHolds.getNodeRefWithoutVersion()).build(),
holdNodeRefTwo);
}
/**
* Valid nodes to be removed from hold
*/
@DataProvider(name = "validNodesToRemoveFromHold")
public Object[][] getValidNodesToRemoveFromHold()
{
//create electronic and nonElectronic record in record folder
RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
RecordFolderAPI recordFolderAPI = getRestAPIFactory().getRecordFolderAPI();
nodesToBeClean.add(recordFolder.getParentId());
Record electronicRecord = recordFolderAPI.createRecord(createElectronicRecordModel(), recordFolder.getId(),
getFile
(IMAGE_FILE));
assertStatusCode(CREATED);
Record nonElectronicRecord = recordFolderAPI.createRecord(createNonElectronicRecordModel(),
recordFolder.getId());
assertStatusCode(CREATED);
RecordCategoryChild folderToHeld = createCategoryFolderInFilePlan();
nodesToBeClean.add(folderToHeld.getParentId());
Stream.of(electronicRecord.getId(), nonElectronicRecord.getId(), folderToHeld.getId())
.forEach(id -> getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(id).build(), holdNodeRefOne));
return new String[][]
{ // record folder
{ folderToHeld.getId() },
//electronic record
{ electronicRecord.getId() },
// non electronic record
{ nonElectronicRecord.getId() },
// document from collaboration site
{ contentHeld.getNodeRefWithoutVersion() },
};
}
/**
* Given content/record folder/record that is held
* And the corresponding hold
* When I use the existing REST API to remove the node from the hold
* Then the node is removed from the hold
* And is no longer frozen
*/
@Test(dataProvider = "validNodesToRemoveFromHold")
public void removeContentFromHold(String nodeId) throws Exception
{
STEP("Remove node from hold");
getRestAPIFactory()
.getHoldsAPI(getAdminUser()).deleteHoldChild(holdNodeRefOne, nodeId);
STEP("Check the node is not held");
assertFalse(hasAspect(nodeId, FROZEN_ASPECT));
STEP("Check node is not in any hold");
RestNodeAssociationModelCollection holdsEntries = getRestAPIFactory()
.getNodeAPI(CoreUtil.toContentModel(nodeId)).usingParams("where=(assocType='rma:frozenContent')")
.getParents();
assertTrue(holdsEntries.getEntries().isEmpty(), "Content held is still added to a hold.");
}
/**
* Given active content that is held on many holds
* When I use the existing REST API to remove the active content from one hold
* Then the active content is removed from the specific hold
* And is frozen
* And in the other holds
*/
@Test
public void removeContentAddedToManyHolds() throws Exception
{
STEP("Remove content from hold. ");
getRestAPIFactory().getHoldsAPI(getAdminUser())
.deleteHoldChild(holdNodeRefOne, contentAddToManyHolds.getNodeRefWithoutVersion());
STEP("Check the content is held. ");
assertTrue(hasAspect(contentAddToManyHolds.getNodeRefWithoutVersion(), FROZEN_ASPECT));
STEP("Check node is in hold HOLD_TWO. ");
RestNodeAssociationModelCollection holdsEntries = getRestAPIFactory()
.getNodeAPI(CoreUtil.toContentModel(contentAddToManyHolds.getNodeRefWithoutVersion()))
.usingParams("where=(assocType='rma:frozenContent')").getParents();
assertFalse(holdsEntries.getEntries().isEmpty(), "Content held is not held after removing from one hold.");
assertTrue(holdsEntries.getEntries().stream()
.anyMatch(restNodeModel -> restNodeModel.getModel().getName().equals(HOLD_TWO)),
"Content held is not held after removing from one hold.");
}
/**
* Data provider with user without right permission or capability to remove from hold a specific node
*
* @return user model and the node ref to be removed from hold
*/
@DataProvider(name = "userWithoutPermissionForRemoveFromHold")
public Object[][] getUserWithoutPermissionForAddToHold()
{
//create record folder
RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
nodesToBeClean.add(recordFolder.getParentId());
UserModel user = roleService.createUserWithRMRole(ROLE_RM_MANAGER.roleId);
getRestAPIFactory().getRMUserAPI().addUserPermission(holdNodeRefOne, user, PERMISSION_FILING);
//create files that will be removed from hold
FileModel contentNoHoldPerm = dataContent.usingAdmin().usingSite(testSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
FileModel contentNoHoldCap = dataContent.usingAdmin().usingSite(testSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
FileModel privateFile = dataContent.usingAdmin().usingSite(privateSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
//add files to hold
asList(recordFolder.getId(), contentNoHoldCap.getNodeRefWithoutVersion(),
contentNoHoldPerm.getNodeRefWithoutVersion(), privateFile.getNodeRefWithoutVersion())
.forEach(id -> getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(id).build(), holdNodeRefOne));
return new Object[][]
{
// user with read permission on the content, with remove from hold capability and without
// filling permission on a hold
{
roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole.SiteCollaborator,
holdNodeRefOne, UserRoles.ROLE_RM_MANAGER, PERMISSION_READ_RECORDS),
contentNoHoldPerm.getNodeRefWithoutVersion()
},
// user with write permission on the content, filling permission on a hold without remove from
// hold capability
{
roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole
.SiteCollaborator,
holdNodeRefOne, UserRoles.ROLE_RM_POWER_USER, PERMISSION_FILING),
contentNoHoldCap.getNodeRefWithoutVersion()
},
//user without read permission on RM record folder
{
user, recordFolder.getId()
},
//user without read permission over the content from the private site
{
user, privateFile.getNodeRefWithoutVersion()
}
};
}
/**
* Given node on hold in a single hold location
* And the user does not have sufficient permissions or capabilities to remove the node from the hold
* When the user tries to remove the node from the hold
* Then it's unsuccessful
*
* @throws Exception
*/
@Test(dataProvider = "userWithoutPermissionForRemoveFromHold")
public void removeFromHoldWithUserWithoutPermission(UserModel userModel, String nodeIdToBeRemoved) throws Exception
{
STEP("Update the list of users to be deleted after running the tests");
usersToBeClean.add(userModel);
STEP("Remove node from hold with user without right permission or capability");
getRestAPIFactory().getHoldsAPI(userModel).deleteHoldChild(holdNodeRefOne, nodeIdToBeRemoved);
assertStatusCode(FORBIDDEN);
getRestAPIFactory().getRmRestWrapper().assertLastError().containsSummary(ACCESS_DENIED_ERROR_MESSAGE);
STEP("Check node is frozen.");
assertTrue(hasAspect(nodeIdToBeRemoved, FROZEN_ASPECT));
}
/**
* Data provider with user with right permission or capability to remove from hold a specific node
*
* @return user model and the node ref to be removed from hold
*/
@DataProvider(name = "userWithPermissionForRemoveFromHold")
public Object[][] getUserWithPermissionForAddToHold()
{
//create record folder
RecordCategoryChild recordFolder = createCategoryFolderInFilePlan();
nodesToBeClean.add(recordFolder.getParentId());
UserModel user = roleService.createUserWithRMRoleAndRMNodePermission(ROLE_RM_MANAGER.roleId,
recordFolder.getId(),
PERMISSION_READ_RECORDS);
getRestAPIFactory().getRMUserAPI().addUserPermission(holdNodeRefOne, user, PERMISSION_FILING);
//create file that will be removed from hold
FileModel contentPermission = dataContent.usingAdmin().usingSite(testSite)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
//add files to hold
asList(recordFolder.getId(), contentPermission.getNodeRefWithoutVersion())
.forEach(id -> getRestAPIFactory()
.getHoldsAPI(getAdminUser())
.addChildToHold(HoldChild.builder().id(id).build(), holdNodeRefOne));
return new Object[][]
{
// user with write permission on the content
{
roleService.createUserWithSiteRoleRMRoleAndPermission(testSite, UserRole.SiteConsumer,
holdNodeRefOne, UserRoles.ROLE_RM_MANAGER, PERMISSION_FILING),
contentPermission.getNodeRefWithoutVersion()
},
//user with read permission on RM record folder
{
user, recordFolder.getId()
},
};
}
@Test(dataProvider = "userWithPermissionForRemoveFromHold")
public void removeFromHoldWithUserWithPermission(UserModel userModel, String nodeIdToBeRemoved) throws Exception
{
STEP("Update the list of users to be deleted after running the tests");
usersToBeClean.add(userModel);
STEP("Remove node from hold with user with right permission and capability");
getRestAPIFactory().getHoldsAPI(userModel).deleteHoldChild(holdNodeRefOne, nodeIdToBeRemoved);
STEP("Check node is not frozen.");
assertFalse(hasAspect(nodeIdToBeRemoved, FROZEN_ASPECT));
}
private Hold createHold(String parentId, Hold hold, UserModel user)
{
FilePlanAPI filePlanAPI = getRestAPIFactory().getFilePlansAPI(user);
return filePlanAPI.createHold(hold, parentId);
}
@AfterClass(alwaysRun = true)
public void cleanUpRemoveContentFromHold()
{
holdsListRef.forEach(holdRef -> getRestAPIFactory().getHoldsAPI(getAdminUser()).deleteHold(holdRef));
dataSite.usingAdmin().deleteSite(testSite);
dataSite.usingAdmin().deleteSite(privateSite);
usersToBeClean.forEach(user -> getDataUser().usingAdmin().deleteUser(user));
nodesToBeClean.forEach(this::deleteRecordCategory);
}
}

View File

@@ -0,0 +1,377 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.retentionschedule;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.retentionschedule.RetentionSchedule;
import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleActionDefinition;
import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleStepCollection;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.alfresco.rest.core.v0.BaseAPI.RM_SITE_ID;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CONFLICT;
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 static org.springframework.http.HttpStatus.UNAUTHORIZED;
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
import static org.testng.Assert.assertNotNull;
import static org.testng.AssertJUnit.assertEquals;
/**
* Retention schedule step test case
*/
public class RetentionScheduleStepTests extends BaseRMRestTest
{
private RecordCategory recordCategory;
private RetentionSchedule createdRetentionSchedule;
private final RetentionScheduleActionDefinition retentionScheduleActionDefinition = new RetentionScheduleActionDefinition();
private RetentionScheduleActionDefinition createdRetentionActionDefinition;
private UserModel nonRMuser;
private final List<String> recordCategories = new ArrayList<>();
private static final String TEST_USER = "testUser";
private static final String RECORD_CATEGORY = "recordCategory";
private static final String PERIOD_PROPERTY = "cm:created";
private static final String AUTHORITY = "authority";
private static final String INSTRUCTIONS = "instructions";
private static final int PERIOD_AMOUNT = 5;
private static final String PERIOD = "month";
private static final List<String> EVENTS = Arrays.asList("case_closed","abolished");
private static final String TRANSFER_STEP = "transfer";
private static final String RETAIN_STEP = "retain";
private static final String INVALID_PERIOD = "random";
private static final String CUTOFF_STEP = "cutoff";
private static final String DESTROY_STEP = "destroyContent";
private static final String INVALID_PASSWORD = "wrongPassword";
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@BeforeClass(alwaysRun = true)
public void preconditionForRetentionScheduleStepTests()
{
createRMSiteIfNotExists();
// create a non rm user
nonRMuser = dataUser.createRandomTestUser(TEST_USER);
//Create record category
recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY));
recordCategories.add(recordCategory.getId());
RetentionSchedule retentionSchedule = new RetentionSchedule();
retentionSchedule.setAuthority(AUTHORITY + getRandomAlphanumeric());
retentionSchedule.setInstructions(INSTRUCTIONS + getRandomAlphanumeric());
retentionSchedule.setIsRecordLevel(false);
//Create retention schedule with a valid user
createdRetentionSchedule = getRestAPIFactory().getRetentionScheduleAPI()
.createRetentionSchedule(retentionSchedule, recordCategory.getId());
retentionScheduleActionDefinition.setName(RETAIN_STEP);
retentionScheduleActionDefinition.setDescription(INSTRUCTIONS);
retentionScheduleActionDefinition.setPeriodAmount(PERIOD_AMOUNT);
retentionScheduleActionDefinition.setPeriodProperty(PERIOD_PROPERTY);
retentionScheduleActionDefinition.setPeriod(PERIOD);
retentionScheduleActionDefinition.setCombineRetentionStepConditions(false);
retentionScheduleActionDefinition.setEligibleOnFirstCompleteEvent(true);
retentionScheduleActionDefinition.setEvents(EVENTS);
}
@Test(priority = 1)
public void createRetentionScheduleStepFor422()
{
RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition();
//Creating the first action "transfer" should give 422
actionDefinition.setName(TRANSFER_STEP);
actionDefinition.setLocation("location");
//Create retention schedule action definition
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,createdRetentionSchedule.getId());
// Verify the status code
assertStatusCode(UNPROCESSABLE_ENTITY);
}
@Test(priority = 2)
public void createRetentionScheduleStepWithInvalidPeriodValue()
{
RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition();
actionDefinition.setName(RETAIN_STEP);
//Invalid period value
actionDefinition.setPeriod(INVALID_PERIOD);
//Create retention schedule action definition
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,createdRetentionSchedule.getId());
// Verify the status code
assertStatusCode(BAD_REQUEST);
}
@Test(priority = 3)
public void createRetentionScheduleWithInvalidStep()
{
RecordCategory recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY));
recordCategories.add(recordCategory.getId());
RetentionSchedule retentionSchedule = createRetentionSchedule(recordCategory);
RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition();
actionDefinition.setName(RETAIN_STEP);
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,retentionSchedule.getId());
assertStatusCode(CREATED);
RetentionScheduleActionDefinition actionDefinition1 = getRetentionScheduleActionDefinition();
actionDefinition1.setName(TRANSFER_STEP);
actionDefinition1.setLocation("location");
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition1,retentionSchedule.getId());
assertStatusCode(CREATED);
RetentionScheduleActionDefinition actionDefinition2 = getRetentionScheduleActionDefinition();
actionDefinition2.setName(CUTOFF_STEP);
//Create retention schedule action definition
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition2,retentionSchedule.getId());
// Verify the status code
assertStatusCode(CONFLICT);
}
@Test(priority = 4)
public void createRetentionScheduleWithInvalidStepAfterDestroy()
{
RecordCategory recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY));
recordCategories.add(recordCategory.getId());
RetentionSchedule retentionSchedule = createRetentionSchedule(recordCategory);
RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition();
actionDefinition.setName(RETAIN_STEP);
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,retentionSchedule.getId());
assertStatusCode(CREATED);
RetentionScheduleActionDefinition actionDefinition1 = getRetentionScheduleActionDefinition();
actionDefinition1.setName(DESTROY_STEP);
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition1,retentionSchedule.getId());
assertStatusCode(CREATED);
RetentionScheduleActionDefinition actionDefinition2 = getRetentionScheduleActionDefinition();
actionDefinition2.setName(CUTOFF_STEP);
//Create retention schedule action definition
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition2,retentionSchedule.getId());
// Verify the status code
assertStatusCode(CONFLICT);
}
@Test(priority = 5)
public void combineRetentionStepConditionsNotValidForNonAccessionStep()
{
RecordCategory recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY));
recordCategories.add(recordCategory.getId());
RetentionSchedule retentionSchedule = createRetentionSchedule(recordCategory);
RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition();
actionDefinition.setName(RETAIN_STEP);
actionDefinition.setCombineRetentionStepConditions(true);
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,retentionSchedule.getId());
assertStatusCode(BAD_REQUEST);
}
@Test(priority = 6)
public void createRetentionScheduleWithSameStep()
{
RecordCategory recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY));
recordCategories.add(recordCategory.getId());
RetentionSchedule retentionSchedule = createRetentionSchedule(recordCategory);
RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition();
actionDefinition.setName(RETAIN_STEP);
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,retentionSchedule.getId());
assertStatusCode(CREATED);
RetentionScheduleActionDefinition actionDefinition1 = getRetentionScheduleActionDefinition();
actionDefinition1.setName(RETAIN_STEP);
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition1,retentionSchedule.getId());
// Verify the status code
assertStatusCode(CONFLICT);
}
@Test(priority = 7)
public void createRetentionScheduleWithMultipleTransferStep()
{
RecordCategory recordCategory = createRootCategory(getRandomName(RECORD_CATEGORY));
recordCategories.add(recordCategory.getId());
RetentionSchedule retentionSchedule = createRetentionSchedule(recordCategory);
RetentionScheduleActionDefinition actionDefinition = getRetentionScheduleActionDefinition();
actionDefinition.setName(RETAIN_STEP);
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition,retentionSchedule.getId());
assertStatusCode(CREATED);
RetentionScheduleActionDefinition actionDefinition1 = getRetentionScheduleActionDefinition();
actionDefinition1.setName(TRANSFER_STEP);
actionDefinition1.setLocation("location");
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition1, retentionSchedule.getId());
RetentionScheduleActionDefinition actionDefinition2 = getRetentionScheduleActionDefinition();
actionDefinition2.setName(TRANSFER_STEP);
actionDefinition2.setLocation("location");
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(actionDefinition2, retentionSchedule.getId());
// Verify the status code
assertStatusCode(CREATED);
}
@Test(priority = 8)
public void createRetentionScheduleStepFor201()
{
//Create retention schedule action definition
createdRetentionActionDefinition = getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(retentionScheduleActionDefinition,createdRetentionSchedule.getId());
// Verify the status code
assertStatusCode(CREATED);
// Find this retention schedule is created one or not
assertEquals(createdRetentionActionDefinition.getName(), retentionScheduleActionDefinition.getName());
assertEquals(createdRetentionActionDefinition.getDescription(), retentionScheduleActionDefinition.getDescription());
assertEquals(createdRetentionActionDefinition.getPeriodAmount(), retentionScheduleActionDefinition.getPeriodAmount());
assertEquals(createdRetentionActionDefinition.isCombineRetentionStepConditions(), retentionScheduleActionDefinition.isCombineRetentionStepConditions());
assertEquals(createdRetentionActionDefinition.isEligibleOnFirstCompleteEvent(), retentionScheduleActionDefinition.isEligibleOnFirstCompleteEvent());
}
@Test(priority = 9)
public void createRetentionScheduleStepFor401()
{
//Create retention schedule action definition
getRestAPIFactory().getRetentionScheduleAPI(new UserModel(getAdminUser().getUsername(), INVALID_PASSWORD)).createRetentionScheduleStep(retentionScheduleActionDefinition,createdRetentionSchedule.getId());
// Verify the status code
assertStatusCode(UNAUTHORIZED);
}
@Test(priority = 10)
public void createRetentionScheduleStepFor403()
{
//Create retention schedule action definition
getRestAPIFactory().getRetentionScheduleAPI(nonRMuser).createRetentionScheduleStep(retentionScheduleActionDefinition,createdRetentionSchedule.getId());
// Verify the status code
assertStatusCode(FORBIDDEN);
}
@Test(priority = 11)
public void retentionScheduleStepFor400()
{
getRestAPIFactory().getRetentionScheduleAPI().getRetentionScheduleStep(recordCategory.getId());
// Verify the status code
assertStatusCode(BAD_REQUEST);
}
@Test(priority = 12)
public void createRetentionScheduleStepFor404()
{
//Create retention schedule action definition
getRestAPIFactory().getRetentionScheduleAPI().createRetentionScheduleStep(retentionScheduleActionDefinition,getRandomAlphanumeric());
// Verify the status code
assertStatusCode(NOT_FOUND);
}
@Test(priority = 13)
public void retentionScheduleStepFor403()
{
// Get retention schedule steps with user having no rights
getRestAPIFactory().getRetentionScheduleAPI(nonRMuser).getRetentionScheduleStep(createdRetentionSchedule.getId());
// Verify the status code
assertStatusCode(FORBIDDEN);
}
@Test(priority = 14)
public void retentionScheduleStepFor401()
{
getRestAPIFactory().getRetentionScheduleAPI(new UserModel(getAdminUser().getUsername(), INVALID_PASSWORD)).getRetentionScheduleStep(createdRetentionSchedule.getId());
// Verify the status code
assertStatusCode(UNAUTHORIZED);
}
@Test(priority = 15)
public void retentionScheduleStepWith200()
{
RetentionScheduleStepCollection receiveRetentionStepCollection = getRestAPIFactory().getRetentionScheduleAPI().getRetentionScheduleStep(createdRetentionSchedule.getId());
// Verify the status code
assertStatusCode(OK);
receiveRetentionStepCollection.getEntries().forEach(c ->
{
RetentionScheduleActionDefinition retentionActionDef = c.getEntry();
assertNotNull(retentionActionDef.getId());
// Find this retention schedule is created one or not
assertEquals(createdRetentionActionDefinition.getId(), retentionActionDef.getId());
assertEquals(createdRetentionActionDefinition.getName(), retentionActionDef.getName());
assertEquals(createdRetentionActionDefinition.getDescription(), retentionActionDef.getDescription());
assertEquals(createdRetentionActionDefinition.getPeriod(), retentionActionDef.getPeriod());
assertEquals(createdRetentionActionDefinition.getPeriodAmount(), retentionActionDef.getPeriodAmount());
assertEquals(createdRetentionActionDefinition.isCombineRetentionStepConditions(), retentionActionDef.isCombineRetentionStepConditions());
assertEquals(createdRetentionActionDefinition.isEligibleOnFirstCompleteEvent(), retentionActionDef.isEligibleOnFirstCompleteEvent());
});
}
private RetentionSchedule createRetentionSchedule(RecordCategory recordCategory)
{
RetentionSchedule retentionSchedule = new RetentionSchedule();
retentionSchedule.setAuthority(AUTHORITY + getRandomAlphanumeric());
retentionSchedule.setInstructions(INSTRUCTIONS + getRandomAlphanumeric());
retentionSchedule.setIsRecordLevel(false);
//Create retention schedule with a valid user
retentionSchedule = getRestAPIFactory().getRetentionScheduleAPI()
.createRetentionSchedule(retentionSchedule, recordCategory.getId());
// Verify the status code
assertStatusCode(CREATED);
return retentionSchedule;
}
private static RetentionScheduleActionDefinition getRetentionScheduleActionDefinition()
{
RetentionScheduleActionDefinition actionDefinition = new RetentionScheduleActionDefinition();
actionDefinition.setDescription(INSTRUCTIONS);
actionDefinition.setPeriodAmount(PERIOD_AMOUNT);
actionDefinition.setPeriodProperty(PERIOD_PROPERTY);
actionDefinition.setPeriod(PERIOD);
actionDefinition.setCombineRetentionStepConditions(false);
actionDefinition.setEligibleOnFirstCompleteEvent(true);
actionDefinition.setEvents(EVENTS);
return actionDefinition;
}
@AfterClass(alwaysRun = true)
public void cleanUpRetentionScheduleStepTests()
{
rmRolesAndActionsAPI.deleteAllItemsInContainer(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), RM_SITE_ID, recordCategory.getName());
recordCategories.forEach(this::deleteRecordCategory);
dataUser.deleteUser(nonRMuser);
}
}

View File

@@ -0,0 +1,270 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.retentionschedule;
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
import org.alfresco.rest.rm.community.model.recordcategory.RecordCategory;
import org.alfresco.rest.rm.community.model.retentionschedule.RetentionSchedule;
import org.alfresco.rest.rm.community.model.retentionschedule.RetentionScheduleCollection;
import org.alfresco.rest.v0.RMRolesAndActionsAPI;
import org.alfresco.utility.model.UserModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import static org.alfresco.rest.core.v0.BaseAPI.RM_SITE_ID;
import static org.alfresco.utility.data.RandomData.getRandomAlphanumeric;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.springframework.http.HttpStatus.CONFLICT;
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 static org.springframework.http.HttpStatus.UNAUTHORIZED;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
import static org.testng.AssertJUnit.assertEquals;
/**
* This class contains the tests for the Retention Schedule CRUD V1 API
*/
public class RetentionScheduleTests extends BaseRMRestTest
{
private RecordCategory recordCategory;
private RetentionSchedule createdRetentionSchedule;
private UserModel nonRMuser;
@Autowired
private RMRolesAndActionsAPI rmRolesAndActionsAPI;
@BeforeClass(alwaysRun = true)
public void preconditionForRetentionScheduleTests()
{
createRMSiteIfNotExists();
// create a non rm user
nonRMuser = dataUser.createRandomTestUser("testUser");
//Create record category
recordCategory = createRootCategory(getRandomName("recordCategory"));
}
/**
* <pre>
* Given that a record category exists
* When I ask the API to create a retention schedule with a user having no rights
* Then it will give 403 as status code
* </pre>
*/
@Test(priority = 1)
public void createRetentionScheduleFor403()
{
RetentionSchedule retentionSchedule = new RetentionSchedule();
// Create retention schedule with user having no rights
getRestAPIFactory().getRetentionScheduleAPI(nonRMuser).createRetentionSchedule(retentionSchedule, recordCategory.getId());
// Verify the status code
assertStatusCode(FORBIDDEN);
}
/**
* <pre>
* Given that a record category does not exists
* When I ask the API to create a retention schedule on a category Id
* Then it will give 404 as a status code
* </pre>
*/
@Test(priority = 2)
public void createRetentionScheduleFor404()
{
RetentionSchedule retentionSchedule = new RetentionSchedule();
//Create retention schedule with category id not exist
getRestAPIFactory().getRetentionScheduleAPI().createRetentionSchedule(retentionSchedule, getRandomAlphanumeric());
// Verify the status code
assertStatusCode(NOT_FOUND);
}
/**
* <pre>
* Given that a record category exists
* When I ask the API to create a retention schedule on a category id with a user having unauthorized access
* Then it will give 401 as a status code
* </pre>
*/
@Test(priority = 3)
public void createRetentionScheduleFor401()
{
RetentionSchedule retentionSchedule = new RetentionSchedule();
//Create retention schedule with a user with unauthorized access
createdRetentionSchedule = getRestAPIFactory().getRetentionScheduleAPI(new UserModel(getAdminUser().getUsername(), "wrongPassword")).createRetentionSchedule(retentionSchedule, recordCategory.getId());
// Verify the status code
assertStatusCode(UNAUTHORIZED);
}
/**
* <pre>
* Given that a record category exists
* When I ask the API to create a retention schedule with a user having access
* Then it is created with a 201 status code
* </pre>
*/
@Test(priority = 4)
public void createRetentionScheduleFor201()
{
RetentionSchedule retentionSchedule = new RetentionSchedule();
String authority = "authority" + getRandomAlphanumeric();
String instructions = "instructions" + getRandomAlphanumeric();
boolean isRecordLevel = false;
retentionSchedule.setAuthority(authority);
retentionSchedule.setInstructions(instructions);
retentionSchedule.setIsRecordLevel(isRecordLevel);
//Create retention schedule with a valid user
createdRetentionSchedule = getRestAPIFactory().getRetentionScheduleAPI()
.createRetentionSchedule(retentionSchedule, recordCategory.getId());
// Verify the status code
assertStatusCode(CREATED);
assertEquals(createdRetentionSchedule.getAuthority(), authority);
assertEquals(createdRetentionSchedule.getInstructions(), instructions);
assertFalse(createdRetentionSchedule.getIsRecordLevel());
assertNotNull(createdRetentionSchedule.getId());
}
/**
* <pre>
* Given that a record category exists
* When I ask the API to create a retention schedule on a category id having retention schedule already
* Then it will give 409 as a status code
* </pre>
*/
@Test(priority = 5)
public void createRetentionScheduleFor409()
{
RetentionSchedule retentionSchedule = new RetentionSchedule();
//Create retention schedule on a category with already having retention schedule
getRestAPIFactory().getRetentionScheduleAPI()
.createRetentionSchedule(retentionSchedule, recordCategory.getId());
assertStatusCode(CONFLICT);
}
/**
* <pre>
* Given that a record category exists
* When I ask the API to get a retention schedule on a given categoryId with a user having no rights
* Then it will give 403
* </pre>
*/
@Test(priority = 6)
public void retentionScheduleWith403()
{
//Get retention schedule with user having no rights
getRestAPIFactory().getRetentionScheduleAPI(nonRMuser).getRetentionSchedule(recordCategory.getId());
// Verify the status code
assertStatusCode(FORBIDDEN);
}
/**
* <pre>
* Given that a record category does not exists
* When I ask the API to get a retention schedule on a category Id
* Then it will give 404 as a status code
* </pre>
*/
@Test(priority = 7)
public void retentionScheduleWith404()
{
//Get retention schedule with category id that does not exist
getRestAPIFactory().getRetentionScheduleAPI().getRetentionSchedule(getRandomAlphanumeric());
// Verify the status code
assertStatusCode(NOT_FOUND);
}
/**
* <pre>
* Given that a record category exists
* When I ask the API to get a retention schedule on a categoryId with a user having unauthorized access
* Then it will give 401 as a status code
* </pre>
*/
@Test(priority = 8)
public void retentionScheduleWith401()
{
//Create retention schedule with a user with unauthorized access
getRestAPIFactory().getRetentionScheduleAPI(new UserModel(getAdminUser().getUsername(), "wrongPassword")).getRetentionSchedule(recordCategory.getId());
// Verify the status code
assertStatusCode(UNAUTHORIZED);
}
/**
* <pre>
* Given that a record category exists
* When I ask the API to get a retention schedule on a categoryId with a user having access
* Then it will give retentionSchedule with 200 as a status code
* </pre>
*/
@Test(priority = 9)
public void retentionScheduleWith200()
{
RetentionScheduleCollection retentionScheduleCollection = getRestAPIFactory().getRetentionScheduleAPI().getRetentionSchedule(recordCategory.getId());
// Verify the status code
assertStatusCode(OK);
retentionScheduleCollection.getEntries().forEach(c ->
{
RetentionSchedule retentionSchedule = c.getEntry();
String retentionScheduleId = retentionSchedule.getId();
assertNotNull(retentionScheduleId);
logger.info("Checking retention schedule " + retentionScheduleId);
// Find this retention schedule is created one or not
assertEquals(createdRetentionSchedule.getId(), retentionScheduleId);
assertEquals(createdRetentionSchedule.getParentId(),retentionSchedule.getParentId());
assertEquals(createdRetentionSchedule.getAuthority(), retentionSchedule.getAuthority());
assertEquals(createdRetentionSchedule.getInstructions(), retentionSchedule.getInstructions());
assertEquals(createdRetentionSchedule.getIsRecordLevel(), retentionSchedule.getIsRecordLevel());
assertEquals(createdRetentionSchedule.isUnpublishedUpdates(), retentionSchedule.isUnpublishedUpdates());
});
}
@AfterClass(alwaysRun = true)
public void cleanUpRetentionScheduleTests()
{
rmRolesAndActionsAPI.deleteAllItemsInContainer(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), RM_SITE_ID, recordCategory.getName());
deleteRecordCategory(recordCategory.getId());
dataUser.deleteUser(nonRMuser);
}
}

View File

@@ -0,0 +1 @@
com.epam.reportportal.testng.ReportPortalTestNGListener

View File

@@ -45,9 +45,9 @@ serverHealth.showTenants=false
# testManagement.username=<username>
# testManagement.apiKey=<api-key>
# testManagement.project=<id-of-your-project
# testManagement.testRun=<test-run-name>
# testManagement.testRun=<test-run-name>
# testManagement.includeOnlyTestCasesExecuted=true #if you want to include in your run ONLY the test cases that you run, then set this value to false
# testManagement.rateLimitInSeconds=1 #is the default rate limit after what minimum time, should we upload the next request. http://docs.gurock.com/testrail-api2/introduction #Rate Limit
# testManagement.rateLimitInSeconds=1 #is the default rate limit after what minimum time, should we upload the next request. http://docs.gurock.com/testrail-api2/introduction #Rate Limit
# testManagement.suiteId=23 (the id of the Master suite)
# ------------------------------------------------------
testManagement.enabled=false
@@ -72,7 +72,7 @@ reports.path=./target/reports
#
# MySQL:
# db.url = jdbc:mysql://${alfresco.server}:3306/alfresco
#
#
# PostgreSQL:
# db.url = jdbc:postgresql://<your-DB-IP>:3306/alfresco
#

View File

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

View File

@@ -139,3 +139,26 @@ content.metadata.async.extract.6.enabled=false
# Max number of entries returned in Record search view
rm.recordSearch.maxItems=500
#
# Hold bulk
#
# The number of worker threads.
rm.hold.bulk.threadCount=2
# The maximum number of total items to process in a single bulk operation.
rm.hold.bulk.maxItems=1000
# The number of entries to be fetched from the Search Service as a next set of work object to process.
rm.hold.bulk.batchSize=100
# The number of entries to process before reporting progress.
rm.hold.bulk.logging.interval=100
# The number of entries we process at a time in a transaction.
rm.hold.bulk.itemsPerTransaction=1
# The maximum number of bulk requests we can process in parallel.
rm.hold.bulk.maxParallelRequests=10
cache.bulkHoldStatusCache.cluster.type=fully-distributed
cache.bulkHoldStatusCache.timeToLiveSeconds=2592000
cache.bulkHoldRegistryCache.cluster.type=fully-distributed
cache.bulkHoldRegistryCache.timeToLiveSeconds=2592000
cache.bulkCancellationsCache.cluster.type=fully-distributed
cache.bulkCancellationsCache.timeToLiveSeconds=2592000

View File

@@ -31,6 +31,11 @@
<cm:description>Configuration information for the Records Management application.</cm:description>
</view:properties>
<view:aspects>
<sys:undeletable/>
<sys:unmovable/>
</view:aspects>
<view:associations>
<cm:contains>

View File

@@ -125,7 +125,7 @@
parent="declarativeCapability">
<property name="name" value="DeleteRecordFolder"/>
<property name="private" value="true"/>
<property name="permission" value="CreateModifyDestroyFolders"/>
<property name="permission" value="DeleteRecords"/>
<property name="kinds">
<list>
<value>RECORD_FOLDER</value>

View File

@@ -538,6 +538,11 @@
<type>d:text</type>
<mandatory>true</mandatory>
</property>
<property name="rma:holdDeletionReason">
<title>Hold Deletion Reason</title>
<type>d:text</type>
<mandatory>false</mandatory>
</property>
</properties>
<associations>

View File

@@ -89,6 +89,9 @@
<!-- Import RM Audit -->
<import resource="classpath:alfresco/module/org_alfresco_module_rm/rm-audit-context.xml"/>
<!-- Import RM Bulk -->
<import resource="classpath:alfresco/module/org_alfresco_module_rm/rm-bulk-context.xml"/>
<!-- Import RM query context -->
<import resource="classpath:alfresco/module/org_alfresco_module_rm/query/rm-query-context.xml" />

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="holdBulkService"
class="org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkServiceImpl">
<property name="serviceRegistry" ref="ServiceRegistry" />
<property name="transactionService" ref="transactionService" />
<property name="searchMapper" ref="searchapiSearchMapper" />
<property name="bulkMonitor" ref="holdBulkMonitor" />
<property name="holdService" ref="HoldService" />
<property name="capabilityService" ref="CapabilityService" />
<property name="permissionService" ref="PermissionService" />
<property name="nodeService" ref="NodeService" />
<property name="threadCount">
<value>${rm.hold.bulk.threadCount}</value>
</property>
<property name="batchSize">
<value>${rm.hold.bulk.batchSize}</value>
</property>
<property name="maxItems">
<value>${rm.hold.bulk.maxItems}</value>
</property>
<property name="loggingInterval">
<value>${rm.hold.bulk.logging.interval}</value>
</property>
<property name="itemsPerTransaction">
<value>${rm.hold.bulk.itemsPerTransaction}</value>
</property>
<property name="maxParallelRequests">
<value>${rm.hold.bulk.maxParallelRequests}</value>
</property>
</bean>
<bean id="holdBulkMonitor" class="org.alfresco.module.org_alfresco_module_rm.bulk.hold.DefaultHoldBulkMonitor">
<property name="holdProgressCache" ref="holdProgressCache" />
<property name="holdProcessRegistry" ref="holdProcessRegistry" />
<property name="bulkCancellationsCache" ref="bulkCancellationsCache" />
</bean>
<bean name="holdProgressCache" factory-bean="cacheFactory" factory-method="createCache">
<constructor-arg value="cache.bulkHoldStatusCache" />
</bean>
<bean name="holdProcessRegistry" factory-bean="cacheFactory" factory-method="createCache">
<constructor-arg value="cache.bulkHoldRegistryCache" />
</bean>
<bean name="bulkCancellationsCache" factory-bean="cacheFactory" factory-method="createCache">
<constructor-arg value="cache.bulkCancellationsCache" />
</bean>
</beans>

View File

@@ -31,6 +31,7 @@
<property name="personService" ref="PersonService"/>
<property name="dispositionService" ref="DispositionService"/>
<property name="serviceRegistry" ref="ServiceRegistry"/>
<property name="recordsManagementServiceRegistry" ref="RecordsManagementServiceRegistry"/>
</bean>
<bean id="searchTypesFactory" class="org.alfresco.rm.rest.api.impl.SearchTypesFactory">
@@ -69,7 +70,40 @@
<property name="transactionService" ref="transactionService" />
</bean>
<bean class="org.alfresco.rm.rest.api.unfiledcontainers.UnfiledContainerEntityResource">
<bean class="org.alfresco.rm.rest.api.fileplans.FilePlanHoldsRelation">
<property name="apiUtils" ref="apiUtils" />
<property name="nodesModelFactory" ref="nodesModelFactory" />
<property name="holdService" ref="HoldService" />
<property name="fileFolderService" ref="FileFolderService" />
<property name="transactionService" ref="transactionService" />
</bean>
<bean class="org.alfresco.rm.rest.api.holds.HoldsEntityResource" >
<property name="holdService" ref="HoldService" />
<property name="apiUtils" ref="apiUtils" />
<property name="nodesModelFactory" ref="nodesModelFactory" />
<property name="fileFolderService" ref="FileFolderService" />
<property name="transactionService" ref="transactionService" />
<property name="holdBulkService" ref="holdBulkService" />
</bean>
<bean class="org.alfresco.rm.rest.api.holds.HoldsBulkStatusesRelation" >
<property name="holdBulkMonitor" ref="holdBulkMonitor" />
<property name="holdBulkService" ref="holdBulkService" />
<property name="apiUtils" ref="apiUtils" />
<property name="permissionService" ref="PermissionService" />
</bean>
<bean class="org.alfresco.rm.rest.api.holds.HoldsChildrenRelation">
<property name="holdService" ref="HoldService" />
<property name="apiUtils" ref="apiUtils" />
<property name="nodesModelFactory" ref="nodesModelFactory" />
<property name="fileFolderService" ref="FileFolderService" />
<property name="transactionService" ref="transactionService" />
<property name="permissionService" ref="PermissionService" />
</bean>
<bean class="org.alfresco.rm.rest.api.unfiledcontainers.UnfiledContainerEntityResource">
<property name="apiUtils" ref="apiUtils" />
<property name="fileFolderService" ref="FileFolderService" />
<property name="nodesModelFactory" ref="nodesModelFactory" />
@@ -114,6 +148,20 @@
<property name="transactionService" ref="transactionService" />
</bean>
<bean class="org.alfresco.rm.rest.api.retentionschedule.RetentionScheduleRelation">
<property name="apiUtils" ref="apiUtils" />
<property name="nodesModelFactory" ref="nodesModelFactory" />
<property name="dispositionService" ref="DispositionService"/>
<property name="nodeService" ref="NodeService"/>
</bean>
<bean class="org.alfresco.rm.rest.api.retentionschedule.RetentionScheduleActionRelation">
<property name="apiUtils" ref="apiUtils" />
<property name="nodesModelFactory" ref="nodesModelFactory" />
<property name="nodeService" ref="NodeService"/>
<property name="recordsManagementServiceRegistry" ref="RecordsManagementServiceRegistry"/>
</bean>
<bean class="org.alfresco.rm.rest.api.recordfolders.RecordFolderEntityResource">
<property name="apiUtils" ref="apiUtils" />
<property name="fileFolderService" ref="FileFolderService" />

View File

@@ -1614,6 +1614,8 @@
org.alfresco.module.org_alfresco_module_rm.hold.HoldService.createHold=RM_CAP.0.rma:filePlanComponent.CreateHold
org.alfresco.module.org_alfresco_module_rm.hold.HoldService.getHoldReason=RM.Read.0
org.alfresco.module.org_alfresco_module_rm.hold.HoldService.setHoldReason=RM_CAP.0.rma:filePlanComponent.EditHold
org.alfresco.module.org_alfresco_module_rm.hold.HoldService.setHoldDeletionReason=RM_CAP.0.rma:filePlanComponent.EditHold
org.alfresco.module.org_alfresco_module_rm.hold.HoldService.updateHold=RM_CAP.0.rma:filePlanComponent.EditHold
org.alfresco.module.org_alfresco_module_rm.hold.HoldService.deleteHold=RM_CAP.0.rma:filePlanComponent.DeleteHold
org.alfresco.module.org_alfresco_module_rm.hold.HoldService.addToHold=RM_CAP.0.rma:filePlanComponent.AddToHold
org.alfresco.module.org_alfresco_module_rm.hold.HoldService.addToHolds=RM_ALLOW

View File

@@ -41,6 +41,8 @@ services:
-Daos.baseUrlOverwrite=http://localhost:8080/alfresco/aos
-Dmessaging.broker.url=\"failover:(tcp://activemq:61616)?timeout=3000&jms.useCompression=true\"
-DlocalTransform.core-aio.url=http://transform-core-aio:8090/
-Drm.hold.bulk.maxItems=5
-Drm.hold.bulk.batchSize=2
"
ports:
- 8080:8080

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>23.2.2.2</version>
<version>23.3.0.87-SNAPSHOT</version>
</parent>
<properties>
@@ -84,6 +84,11 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.epam.reportportal</groupId>
<artifactId>agent-java-testng</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
@@ -150,6 +155,12 @@
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>${dependency.awaitility.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@@ -27,6 +27,7 @@
package org.alfresco.module.org_alfresco_module_rm.audit.event;
import static org.alfresco.module.org_alfresco_module_rm.audit.event.HoldUtils.HOLD_DELETION_REASON;
import static org.alfresco.repo.policy.Behaviour.NotificationFrequency.EVERY_EVENT;
import java.io.Serializable;
@@ -77,6 +78,8 @@ public class DeleteHoldAuditEvent extends AuditEvent implements NodeServicePolic
public void beforeDeleteNode(NodeRef holdNodeRef)
{
Map<QName, Serializable> auditProperties = HoldUtils.makePropertiesMap(holdNodeRef, nodeService);
auditProperties.put(HOLD_DELETION_REASON, nodeService.getProperty(holdNodeRef, PROP_HOLD_DELETION_REASON));
recordsManagementAuditService.auditEvent(holdNodeRef, getName(), auditProperties, null, true, false);
}
}

View File

@@ -47,6 +47,7 @@ class HoldUtils
{
/** A QName to display for the hold name. */
public static final QName HOLD_NAME = QName.createQName(RecordsManagementModel.RM_URI, "Hold Name");
public static final QName HOLD_DELETION_REASON = QName.createQName(RecordsManagementModel.RM_URI, "Hold deletion reason");
/** A QName to display for the hold node ref. */
public static final QName HOLD_NODEREF = QName.createQName(RecordsManagementModel.RM_URI, "Hold NodeRef");

View File

@@ -0,0 +1,265 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk;
import static java.util.concurrent.Executors.newFixedThreadPool;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import org.alfresco.repo.batch.BatchProcessWorkProvider;
import org.alfresco.repo.batch.BatchProcessor;
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
import org.alfresco.rest.api.search.impl.SearchMapper;
import org.alfresco.rest.api.search.model.Query;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.search.SearchService;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* A base class for executing bulk operations on nodes based on search query results
*/
public abstract class BulkBaseService<T> implements InitializingBean
{
private static final Log LOG = LogFactory.getLog(BulkBaseService.class);
protected ExecutorService executorService;
protected ServiceRegistry serviceRegistry;
protected SearchService searchService;
protected TransactionService transactionService;
protected SearchMapper searchMapper;
protected BulkMonitor<T> bulkMonitor;
protected int threadCount;
protected int batchSize;
protected int itemsPerTransaction;
protected int maxItems;
protected int loggingInterval;
protected int maxParallelRequests;
@Override
public void afterPropertiesSet() throws Exception
{
this.searchService = serviceRegistry.getSearchService();
this.executorService = newFixedThreadPool(maxParallelRequests);
}
/**
* Execute bulk operation on node based on the search query results
*
* @param nodeRef node reference
* @param bulkOperation bulk operation
* @return bulk status
*/
public T execute(NodeRef nodeRef, BulkOperation bulkOperation)
{
checkPermissions(nodeRef, bulkOperation);
ResultSet resultSet = getTotalItems(bulkOperation.searchQuery(), maxItems);
if (maxItems < resultSet.getNumberFound() || resultSet.hasMore())
{
throw new InvalidArgumentException("Too many items to process. Please refine your query.");
}
long totalItems = resultSet.getNumberFound();
// Generate a random process id
String processId = UUID.randomUUID().toString();
T initBulkStatus = getInitBulkStatus(processId, totalItems);
bulkMonitor.updateBulkStatus(initBulkStatus);
bulkMonitor.registerProcess(nodeRef, processId, bulkOperation);
BulkProgress bulkProgress = new BulkProgress(totalItems, processId, new AtomicBoolean(false),
new AtomicInteger(0));
BatchProcessWorker<NodeRef> batchProcessWorker = getWorkerProvider(nodeRef, bulkOperation, bulkProgress);
BulkStatusUpdater bulkStatusUpdater = getBulkStatusUpdater();
BatchProcessor<NodeRef> batchProcessor = new BatchProcessor<>(
processId,
transactionService.getRetryingTransactionHelper(),
getWorkProvider(bulkOperation, bulkStatusUpdater, bulkProgress),
threadCount,
itemsPerTransaction,
bulkStatusUpdater,
LOG,
loggingInterval);
runAsyncBatchProcessor(batchProcessor, batchProcessWorker, bulkStatusUpdater);
return initBulkStatus;
}
/**
* Run batch processor
*/
protected void runAsyncBatchProcessor(BatchProcessor<NodeRef> batchProcessor,
BatchProcessWorker<NodeRef> batchProcessWorker, BulkStatusUpdater bulkStatusUpdater)
{
Runnable backgroundLogic = () -> {
try
{
if (LOG.isDebugEnabled())
{
LOG.debug("Started processing batch with name: " + batchProcessor.getProcessName());
}
batchProcessor.processLong(batchProcessWorker, true);
if (LOG.isDebugEnabled())
{
LOG.debug("Processing batch with name: " + batchProcessor.getProcessName() + " completed");
}
}
catch (Exception exception)
{
LOG.error("Error processing batch with name: " + batchProcessor.getProcessName(), exception);
}
finally
{
bulkStatusUpdater.update();
}
};
executorService.submit(backgroundLogic);
}
/**
* Get initial bulk status
*
* @param processId process id
* @param totalItems total items
* @return bulk status
*/
protected abstract T getInitBulkStatus(String processId, long totalItems);
/**
* Get bulk status updater
*
* @return bulk status updater
*/
protected abstract BulkStatusUpdater getBulkStatusUpdater();
/**
* Get work provider
*
* @param bulkOperation bulk operation
* @param bulkStatusUpdater bulk status updater
* @param bulkProgress bulk progress
* @return work provider
*/
protected abstract BatchProcessWorkProvider<NodeRef> getWorkProvider(BulkOperation bulkOperation,
BulkStatusUpdater bulkStatusUpdater, BulkProgress bulkProgress);
/**
* Get worker provider
*
* @param nodeRef node reference
* @param bulkOperation bulk operation
* @param bulkProgress bulk progress
* @return worker provider
*/
protected abstract BatchProcessWorker<NodeRef> getWorkerProvider(NodeRef nodeRef, BulkOperation bulkOperation,
BulkProgress bulkProgress);
/**
* Check permissions
*
* @param nodeRef node reference
* @param bulkOperation bulk operation
*/
protected abstract void checkPermissions(NodeRef nodeRef, BulkOperation bulkOperation);
protected ResultSet getTotalItems(Query searchQuery, int skipCount)
{
SearchParameters searchParams = new SearchParameters();
searchMapper.setDefaults(searchParams);
searchMapper.fromQuery(searchParams, searchQuery);
searchParams.setSkipCount(skipCount);
searchParams.setMaxItems(1);
searchParams.setLimit(1);
return searchService.query(searchParams);
}
public void setServiceRegistry(ServiceRegistry serviceRegistry)
{
this.serviceRegistry = serviceRegistry;
}
public void setSearchService(SearchService searchService)
{
this.searchService = searchService;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
public void setSearchMapper(SearchMapper searchMapper)
{
this.searchMapper = searchMapper;
}
public void setBulkMonitor(BulkMonitor<T> bulkMonitor)
{
this.bulkMonitor = bulkMonitor;
}
public void setThreadCount(int threadCount)
{
this.threadCount = threadCount;
}
public void setBatchSize(int batchSize)
{
this.batchSize = batchSize;
}
public void setMaxItems(int maxItems)
{
this.maxItems = maxItems;
}
public void setLoggingInterval(int loggingInterval)
{
this.loggingInterval = loggingInterval;
}
public void setItemsPerTransaction(int itemsPerTransaction)
{
this.itemsPerTransaction = itemsPerTransaction;
}
public void setMaxParallelRequests(int maxParallelRequests)
{
this.maxParallelRequests = maxParallelRequests;
}
}

View File

@@ -0,0 +1,34 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk;
/**
* An immutable POJO to represent a bulk cancellation request
*/
public record BulkCancellationRequest(String reason)
{
}

View File

@@ -0,0 +1,83 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* An interface for monitoring the progress of a bulk operation
*/
public interface BulkMonitor<T>
{
/**
* Update the bulk status
*
* @param bulkStatus the bulk status
*/
void updateBulkStatus(T bulkStatus);
/**
* Register a process
*
* @param nodeRef the node reference
* @param processId the process id
* @param bulkOperation the bulk operation
*/
void registerProcess(NodeRef nodeRef, String processId, BulkOperation bulkOperation);
/**
* Get the bulk status
*
* @param bulkStatusId the bulk status id
* @return the bulk status
*/
T getBulkStatus(String bulkStatusId);
/**
* Cancel a bulk operation
*
* @param bulkStatusId
* @param bulkCancellationRequest
*/
void cancelBulkOperation(String bulkStatusId, BulkCancellationRequest bulkCancellationRequest);
/**
* Check if a bulk operation is cancelled
*
* @param bulkStatusId
* @return true if the bulk operation is cancelled
*/
boolean isCancelled(String bulkStatusId);
/**
* Get the bulk cancellation request
*
* @param bulkStatusId
* @return cancellation reason
*/
BulkCancellationRequest getBulkCancellationRequest(String bulkStatusId);
}

View File

@@ -0,0 +1,46 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk;
import java.io.Serializable;
import org.alfresco.rest.api.search.model.Query;
/**
* An immutable POJO to represent a bulk operation
*/
public record BulkOperation(Query searchQuery, String operationType) implements Serializable
{
public BulkOperation
{
if (operationType == null || searchQuery == null)
{
throw new IllegalArgumentException("Operation type and search query must not be null");
}
}
}

View File

@@ -0,0 +1,37 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* An immutable POJO to represent the progress of a bulk operation
*/
public record BulkProgress(long totalItems, String processId, AtomicBoolean cancelled, AtomicInteger currentNodeNumber)
{
}

View File

@@ -0,0 +1,40 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk;
import org.springframework.context.ApplicationEventPublisher;
/**
* An interface for updating the status of a bulk operation
*/
public interface BulkStatusUpdater extends ApplicationEventPublisher
{
/**
* Update the bulk status
*/
void update();
}

View File

@@ -0,0 +1,165 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk.hold;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkCancellationRequest;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkOperation;
import org.alfresco.repo.cache.SimpleCache;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.Pair;
import org.springframework.context.ApplicationEvent;
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
/**
* Default hold bulk monitor implementation
*/
public class DefaultHoldBulkMonitor extends AbstractLifecycleBean implements HoldBulkMonitor
{
protected SimpleCache<String, HoldBulkStatus> holdProgressCache;
protected SimpleCache<String, BulkCancellationRequest> bulkCancellationsCache;
protected SimpleCache<Pair<String, String>, HoldBulkProcessDetails> holdProcessRegistry;
@Override
public void updateBulkStatus(HoldBulkStatus holdBulkStatus)
{
holdProgressCache.put(holdBulkStatus.bulkStatusId(), holdBulkStatus);
}
@Override
public void registerProcess(NodeRef holdRef, String processId, BulkOperation bulkOperation)
{
if (holdRef != null && processId != null)
{
holdProcessRegistry.put(new Pair<>(holdRef.getId(), processId),
new HoldBulkProcessDetails(processId, getCurrentInstanceDetails(), bulkOperation));
}
}
@Override
public HoldBulkStatus getBulkStatus(String bulkStatusId)
{
return holdProgressCache.get(bulkStatusId);
}
@Override
public void cancelBulkOperation(String bulkStatusId, BulkCancellationRequest bulkCancellationRequest)
{
bulkCancellationsCache.put(bulkStatusId, bulkCancellationRequest);
}
@Override
public boolean isCancelled(String bulkStatusId)
{
return bulkCancellationsCache.contains(bulkStatusId);
}
@Override
public BulkCancellationRequest getBulkCancellationRequest(String bulkStatusId)
{
return bulkCancellationsCache.get(bulkStatusId);
}
@Override
public List<HoldBulkStatusAndProcessDetails> getBulkStatusesWithProcessDetails(String holdId)
{
return holdProcessRegistry.getKeys().stream()
.filter(holdIdAndBulkStatusId -> holdId.equals(holdIdAndBulkStatusId.getFirst()))
.map(holdIdAndBulkStatusId -> holdProcessRegistry.get(holdIdAndBulkStatusId))
.filter(Objects::nonNull)
.map(createHoldBulkStatusAndProcessDetails())
.filter(statusAndProcess -> Objects.nonNull(statusAndProcess.holdBulkStatus()))
.sorted(sortBulkStatuses())
.toList();
}
@Override
public HoldBulkStatusAndProcessDetails getBulkStatusWithProcessDetails(String holdId, String bulkStatusId)
{
return Optional.ofNullable(holdProcessRegistry.get(new Pair<>(holdId, bulkStatusId)))
.map(createHoldBulkStatusAndProcessDetails())
.filter(statusAndProcess -> Objects.nonNull(statusAndProcess.holdBulkStatus()))
.orElse(null);
}
protected String getCurrentInstanceDetails()
{
return null;
}
protected Function<HoldBulkProcessDetails, HoldBulkStatusAndProcessDetails> createHoldBulkStatusAndProcessDetails()
{
return bulkProcessDetails -> new HoldBulkStatusAndProcessDetails(
getBulkStatus(bulkProcessDetails.bulkStatusId()), bulkProcessDetails);
}
protected static Comparator<HoldBulkStatusAndProcessDetails> sortBulkStatuses()
{
return Comparator.<HoldBulkStatusAndProcessDetails, Date>comparing(
statusAndProcess -> statusAndProcess.holdBulkStatus().endTime(),
Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(statusAndProcess -> statusAndProcess.holdBulkStatus().startTime(),
Comparator.nullsLast(Comparator.naturalOrder()))
.reversed();
}
public void setHoldProgressCache(
SimpleCache<String, HoldBulkStatus> holdProgressCache)
{
this.holdProgressCache = holdProgressCache;
}
public void setHoldProcessRegistry(
SimpleCache<Pair<String, String>, HoldBulkProcessDetails> holdProcessRegistry)
{
this.holdProcessRegistry = holdProcessRegistry;
}
public void setBulkCancellationsCache(
SimpleCache<String, BulkCancellationRequest> bulkCancellationsCache)
{
this.bulkCancellationsCache = bulkCancellationsCache;
}
@Override
protected void onBootstrap(ApplicationEvent applicationEvent)
{
// NOOP
}
@Override
protected void onShutdown(ApplicationEvent applicationEvent)
{
// NOOP
}
}

View File

@@ -0,0 +1,54 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk.hold;
import java.util.List;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkMonitor;
/**
* An interface for monitoring the progress of a bulk hold operation
*/
public interface HoldBulkMonitor extends BulkMonitor<HoldBulkStatus>
{
/**
* Get the bulk statuses with process details for a hold
*
* @param holdId the hold id
* @return the bulk statuses with process details
*/
List<HoldBulkStatusAndProcessDetails> getBulkStatusesWithProcessDetails(String holdId);
/**
* Get the bulk status with process details
*
* @param holdId the hold id
* @param bulkStatusId the bulk status id
* @return the bulk status with process details
*/
HoldBulkStatusAndProcessDetails getBulkStatusWithProcessDetails(String holdId, String bulkStatusId);
}

View File

@@ -0,0 +1,38 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk.hold;
import java.io.Serializable;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkOperation;
/**
* A simple immutable POJO to hold the details of a bulk process
*/
public record HoldBulkProcessDetails(String bulkStatusId, String creatorInstance, BulkOperation bulkOperation) implements Serializable
{
}

View File

@@ -0,0 +1,55 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk.hold;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkCancellationRequest;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkOperation;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Interface defining a hold bulk service.
*/
public interface HoldBulkService
{
/**
* Initiates a bulk operation on a hold.
*
* @param holdRef The hold reference
* @param bulkOperation The bulk operation
* @return The initial status of the bulk operation
*/
HoldBulkStatus execute(NodeRef holdRef, BulkOperation bulkOperation);
/**
* Cancels a bulk operation.
*
* @param holdRef The hold reference
* @param bulkStatusId The bulk status id
* @param bulkCancellationRequest The bulk cancellation request
*/
void cancelBulkOperation(NodeRef holdRef, String bulkStatusId, BulkCancellationRequest bulkCancellationRequest);
}

View File

@@ -0,0 +1,286 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk.hold;
import static org.alfresco.model.ContentModel.PROP_NAME;
import static org.alfresco.rm.rest.api.model.HoldBulkOperationType.ADD;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Optional;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkBaseService;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkCancellationRequest;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkOperation;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkProgress;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkStatusUpdater;
import org.alfresco.module.org_alfresco_module_rm.capability.CapabilityService;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.repo.batch.BatchProcessWorkProvider;
import org.alfresco.repo.batch.BatchProcessor.BatchProcessWorker;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.rest.api.search.model.Query;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rm.rest.api.model.HoldBulkOperationType;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.search.ResultSet;
import org.alfresco.service.cmr.search.SearchParameters;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* Implementation of the {@link HoldBulkService} interface.
*/
@SuppressWarnings("PMD.PreserveStackTrace")
public class HoldBulkServiceImpl extends BulkBaseService<HoldBulkStatus> implements HoldBulkService
{
private static final Logger LOGGER = LoggerFactory.getLogger(HoldBulkServiceImpl.class);
private static final String MSG_ERR_ACCESS_DENIED = "permissions.err_access_denied";
private HoldService holdService;
private CapabilityService capabilityService;
private PermissionService permissionService;
private NodeService nodeService;
@Override
protected HoldBulkStatus getInitBulkStatus(String processId, long totalItems)
{
return new HoldBulkStatus(processId, null, null, 0, 0, totalItems, null, false, null);
}
@Override
protected BulkStatusUpdater getBulkStatusUpdater()
{
return new HoldBulkStatusUpdater((HoldBulkMonitor) bulkMonitor);
}
@Override
protected BatchProcessWorkProvider<NodeRef> getWorkProvider(BulkOperation bulkOperation,
BulkStatusUpdater bulkStatusUpdater, BulkProgress bulkProgress)
{
return new AddToHoldWorkerProvider(bulkOperation, bulkStatusUpdater, bulkProgress,
(HoldBulkMonitor) bulkMonitor);
}
@Override
protected BatchProcessWorker<NodeRef> getWorkerProvider(NodeRef nodeRef, BulkOperation bulkOperation,
BulkProgress bulkProgress)
{
try
{
HoldBulkOperationType holdBulkOperationType = HoldBulkOperationType.valueOf(bulkOperation.operationType()
.toUpperCase(Locale.ENGLISH));
return switch (holdBulkOperationType)
{
case ADD -> new AddToHoldWorkerBatch(nodeRef, bulkProgress);
};
}
catch (IllegalArgumentException e)
{
String errorMsg = "Unsupported action type when starting the bulk process: ";
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("{} {}", errorMsg, bulkOperation.operationType(), e);
}
throw new InvalidArgumentException(errorMsg + bulkOperation.operationType());
}
}
@Override
protected void checkPermissions(NodeRef holdRef, BulkOperation bulkOperation)
{
if (!holdService.isHold(holdRef))
{
final String holdName = (String) nodeService.getProperty(holdRef, PROP_NAME);
throw new InvalidArgumentException(I18NUtil.getMessage("rm.hold.not-hold", holdName), null);
}
if (ADD.name().equals(bulkOperation.operationType()) && (!AccessStatus.ALLOWED.equals(
capabilityService.getCapabilityAccessState(holdRef, RMPermissionModel.ADD_TO_HOLD)) ||
permissionService.hasPermission(holdRef, RMPermissionModel.FILING) == AccessStatus.DENIED))
{
throw new AccessDeniedException(I18NUtil.getMessage(MSG_ERR_ACCESS_DENIED));
}
}
@Override
public void cancelBulkOperation(NodeRef holdRef, String bulkStatusId, BulkCancellationRequest cancellationRequest)
{
if (bulkMonitor instanceof HoldBulkMonitor holdBulkMonitor)
{
HoldBulkStatusAndProcessDetails statusAndProcessDetails = holdBulkMonitor.getBulkStatusWithProcessDetails(
holdRef.getId(), bulkStatusId);
Optional.ofNullable(statusAndProcessDetails).map(HoldBulkStatusAndProcessDetails::holdBulkProcessDetails)
.map(HoldBulkProcessDetails::bulkOperation).ifPresent(bulkOperation -> {
checkPermissions(holdRef, bulkOperation);
holdBulkMonitor.cancelBulkOperation(bulkStatusId, cancellationRequest);
});
}
}
private class AddToHoldWorkerBatch implements BatchProcessWorker<NodeRef>
{
private final NodeRef holdRef;
private final String currentUser;
private final BulkProgress bulkProgress;
public AddToHoldWorkerBatch(NodeRef holdRef, BulkProgress bulkProgress)
{
this.holdRef = holdRef;
this.bulkProgress = bulkProgress;
currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
}
@Override
public String getIdentifier(NodeRef entry)
{
return entry.getId();
}
@Override
public void beforeProcess()
{
AuthenticationUtil.pushAuthentication();
}
@Override
public void process(NodeRef entry) throws Throwable
{
if (!bulkProgress.cancelled().get())
{
AuthenticationUtil.setFullyAuthenticatedUser(currentUser);
holdService.addToHold(holdRef, entry);
}
}
@Override
public void afterProcess()
{
AuthenticationUtil.popAuthentication();
}
}
private class AddToHoldWorkerProvider implements BatchProcessWorkProvider<NodeRef>
{
private final HoldBulkMonitor holdBulkMonitor;
private final Query searchQuery;
private final String currentUser;
private final BulkProgress bulkProgress;
private final BulkStatusUpdater bulkStatusUpdater;
public AddToHoldWorkerProvider(BulkOperation bulkOperation,
BulkStatusUpdater bulkStatusUpdater, BulkProgress bulkProgress, HoldBulkMonitor holdBulkMonitor)
{
this.searchQuery = bulkOperation.searchQuery();
this.bulkProgress = bulkProgress;
this.bulkStatusUpdater = bulkStatusUpdater;
this.holdBulkMonitor = holdBulkMonitor;
currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
}
@Override
public int getTotalEstimatedWorkSize()
{
return (int) bulkProgress.totalItems();
}
@Override
public long getTotalEstimatedWorkSizeLong()
{
return bulkProgress.totalItems();
}
@Override
public Collection<NodeRef> getNextWork()
{
AuthenticationUtil.pushAuthentication();
AuthenticationUtil.setFullyAuthenticatedUser(currentUser);
if (holdBulkMonitor.isCancelled(bulkProgress.processId()))
{
bulkProgress.cancelled().set(true);
return Collections.emptyList();
}
SearchParameters searchParams = getNextPageParameters();
ResultSet result = searchService.query(searchParams);
if (result.getNodeRefs().isEmpty())
{
return Collections.emptyList();
}
AuthenticationUtil.popAuthentication();
if (LOGGER.isDebugEnabled())
{
LOGGER.debug("Processing the next work for the batch processor, skipCount={}, size={}",
searchParams.getSkipCount(), result.getNumberFound());
}
bulkProgress.currentNodeNumber().addAndGet(batchSize);
bulkStatusUpdater.update();
return result.getNodeRefs();
}
private SearchParameters getNextPageParameters()
{
SearchParameters searchParams = new SearchParameters();
searchMapper.setDefaults(searchParams);
searchMapper.fromQuery(searchParams, searchQuery);
searchParams.setSkipCount(bulkProgress.currentNodeNumber().get());
searchParams.setMaxItems(batchSize);
searchParams.setLimit(batchSize);
searchParams.addSort("@" + ContentModel.PROP_CREATED, true);
return searchParams;
}
}
public void setHoldService(HoldService holdService)
{
this.holdService = holdService;
}
public void setCapabilityService(CapabilityService capabilityService)
{
this.capabilityService = capabilityService;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
}

View File

@@ -0,0 +1,78 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk.hold;
import java.io.Serializable;
import java.util.Date;
/**
* An immutable POJO that contains the status of a hold bulk operation
*/
public record HoldBulkStatus(String bulkStatusId, Date startTime, Date endTime, long processedItems, long errorsCount,
long totalItems, String lastError, boolean isCancelled, String cancellationReason)
implements Serializable
{
public enum Status
{
PENDING("PENDING"),
IN_PROGRESS("IN PROGRESS"),
DONE("DONE"),
CANCELLED("CANCELLED");
private final String value;
Status(String value)
{
this.value = value;
}
public String getValue()
{
return value;
}
}
public String getStatus()
{
if (isCancelled)
{
return Status.CANCELLED.getValue();
}
else if (startTime == null && endTime == null)
{
return Status.PENDING.getValue();
}
else if (startTime != null && endTime == null)
{
return Status.IN_PROGRESS.getValue();
}
else
{
return Status.DONE.getValue();
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk.hold;
/**
* An immutable POJO that contains the status of a hold bulk operation and the details of the process
*/
public record HoldBulkStatusAndProcessDetails(HoldBulkStatus holdBulkStatus,
HoldBulkProcessDetails holdBulkProcessDetails)
{
}

View File

@@ -0,0 +1,77 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk.hold;
import java.util.Optional;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkCancellationRequest;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkStatusUpdater;
import org.alfresco.repo.batch.BatchMonitor;
import org.alfresco.repo.batch.BatchMonitorEvent;
/**
* An implementation of {@link BulkStatusUpdater} for the hold bulk operation
*/
public class HoldBulkStatusUpdater implements BulkStatusUpdater
{
private final Runnable task;
private BatchMonitor batchMonitor;
public HoldBulkStatusUpdater(HoldBulkMonitor holdBulkMonitor)
{
this.task = () -> holdBulkMonitor.updateBulkStatus(
new HoldBulkStatus(batchMonitor.getProcessName(),
batchMonitor.getStartTime(),
batchMonitor.getEndTime(),
batchMonitor.getSuccessfullyProcessedEntriesLong() + batchMonitor.getTotalErrorsLong(),
batchMonitor.getTotalErrorsLong(),
batchMonitor.getTotalResultsLong(),
batchMonitor.getLastError(),
holdBulkMonitor.isCancelled(batchMonitor.getProcessName()),
Optional.ofNullable(holdBulkMonitor.getBulkCancellationRequest(batchMonitor.getProcessName()))
.map(BulkCancellationRequest::reason)
.orElse(null)));
}
@Override
public void update()
{
if (task != null && batchMonitor != null)
{
task.run();
}
}
@Override
public void publishEvent(Object event)
{
if (event instanceof BatchMonitorEvent batchMonitorEvent)
{
batchMonitor = batchMonitorEvent.getBatchMonitor();
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.module.org_alfresco_module_rm.bulk.hold;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkOperation;
import org.alfresco.rest.api.search.model.Query;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rm.rest.api.model.HoldBulkOperation;
import org.alfresco.rm.rest.api.model.HoldBulkOperationType;
import org.alfresco.rm.rest.api.model.HoldBulkStatusEntry;
/**
* Utility class for hold bulk operations
*/
@SuppressWarnings("PMD.PreserveStackTrace")
public final class HoldBulkUtils
{
private HoldBulkUtils()
{
}
public static HoldBulkStatusEntry toHoldBulkStatusEntry(
HoldBulkStatusAndProcessDetails holdBulkStatusAndProcessDetails)
{
HoldBulkStatus bulkStatus = holdBulkStatusAndProcessDetails.holdBulkStatus();
BulkOperation bulkOperation = holdBulkStatusAndProcessDetails.holdBulkProcessDetails().bulkOperation();
try
{
HoldBulkOperation holdBulkOperation = new HoldBulkOperation(
new Query(bulkOperation.searchQuery().getLanguage(),
bulkOperation.searchQuery().getQuery(), bulkOperation.searchQuery().getUserQuery()),
HoldBulkOperationType.valueOf(bulkOperation.operationType()));
return new HoldBulkStatusEntry(bulkStatus.bulkStatusId(), bulkStatus.startTime(),
bulkStatus.endTime(), bulkStatus.processedItems(), bulkStatus.errorsCount(),
bulkStatus.totalItems(), bulkStatus.lastError(), bulkStatus.getStatus(),
bulkStatus.cancellationReason(), holdBulkOperation);
}
catch (IllegalArgumentException e)
{
String errorMsg = "Unsupported action type in the bulk operation: ";
throw new InvalidArgumentException(errorMsg + bulkOperation.operationType());
}
}
}

View File

@@ -31,7 +31,6 @@ import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
import org.alfresco.module.org_alfresco_module_rm.capability.declarative.DeclarativeCapability;
import org.alfresco.module.org_alfresco_module_rm.record.RecordService;
import org.alfresco.module.org_alfresco_module_rm.recordfolder.RecordFolderService;
@@ -76,7 +75,7 @@ public class CreateCapability extends DeclarativeCapability
@Override
public int evaluate(NodeRef nodeRef)
{
return evaluate(nodeRef, null, null);
return evaluate(nodeRef, null, null, null);
}
/**
@@ -85,9 +84,10 @@ public class CreateCapability extends DeclarativeCapability
* @param destination destination node reference
* @param linkee linkee node reference, can be null
* @param assocType association type, can be null
* @param recordType record type, can be null
* @return
*/
public int evaluate(NodeRef destination, NodeRef linkee, QName assocType)
public int evaluate(NodeRef destination, NodeRef linkee, QName assocType, QName recordType)
{
if (linkee != null)
{
@@ -105,7 +105,7 @@ public class CreateCapability extends DeclarativeCapability
{
if (recordService.isRecord(destination) &&
!recordService.isDeclared(destination) &&
permissionService.hasPermission(destination, RMPermissionModel.FILE_RECORDS) == AccessStatus.ALLOWED)
permissionService.hasPermission(destination, FILE_RECORDS) == AccessStatus.ALLOWED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
@@ -115,7 +115,7 @@ public class CreateCapability extends DeclarativeCapability
if (recordService.isRecord(linkee) &&
recordService.isRecord(destination) &&
!recordService.isDeclared(destination) &&
permissionService.hasPermission(destination, RMPermissionModel.FILE_RECORDS) == AccessStatus.ALLOWED)
permissionService.hasPermission(destination, FILE_RECORDS) == AccessStatus.ALLOWED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
@@ -132,14 +132,15 @@ public class CreateCapability extends DeclarativeCapability
// if the destination folder is not a record folder and the user has filling capability on it, grant access to create the record
if (checkConditions(destination, conditions) &&
!recordFolderService.isRecordFolder(destination) )
!recordFolderService.isRecordFolder(destination) &&
permissionService.hasPermission(destination, CREATE_MODIFY_DESTROY_FILEPLAN_METADATA) == AccessStatus.ALLOWED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
if (checkConditions(destination, conditions) &&
recordFolderService.isRecordFolder(destination) &&
permissionService.hasPermission(destination, RMPermissionModel.FILE_RECORDS) == AccessStatus.ALLOWED)
permissionService.hasPermission(destination, FILE_RECORDS) == AccessStatus.ALLOWED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
@@ -147,7 +148,7 @@ public class CreateCapability extends DeclarativeCapability
conditions.put("capabilityCondition.closed", Boolean.TRUE);
if (checkConditions(destination, conditions) &&
recordFolderService.isRecordFolder(destination) &&
permissionService.hasPermission(getFilePlanService().getFilePlan(destination), RMPermissionModel.DECLARE_RECORDS_IN_CLOSED_FOLDERS) == AccessStatus.ALLOWED)
permissionService.hasPermission(getFilePlanService().getFilePlan(destination), DECLARE_RECORDS_IN_CLOSED_FOLDERS) == AccessStatus.ALLOWED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
@@ -156,32 +157,32 @@ public class CreateCapability extends DeclarativeCapability
conditions.put("capabilityCondition.cutoff", Boolean.TRUE);
if (checkConditions(destination, conditions) &&
recordFolderService.isRecordFolder(destination) &&
permissionService.hasPermission(getFilePlanService().getFilePlan(destination), RMPermissionModel.CREATE_MODIFY_RECORDS_IN_CUTOFF_FOLDERS) == AccessStatus.ALLOWED)
permissionService.hasPermission(getFilePlanService().getFilePlan(destination), CREATE_MODIFY_RECORDS_IN_CUTOFF_FOLDERS) == AccessStatus.ALLOWED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
}
if (capabilityService.getCapability(RMPermissionModel.CREATE_MODIFY_DESTROY_FOLDERS).evaluate(destination) == AccessDecisionVoter.ACCESS_GRANTED)
if (null != recordType && recordType.equals(TYPE_RECORD_FOLDER) && capabilityService.getCapability(CREATE_MODIFY_DESTROY_FOLDERS).evaluate(destination) == AccessDecisionVoter.ACCESS_GRANTED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
if (capabilityService.getCapability(RMPermissionModel.DECLARE_RECORDS_IN_CLOSED_FOLDERS).evaluate(destination) == AccessDecisionVoter.ACCESS_GRANTED)
if (capabilityService.getCapability(DECLARE_RECORDS_IN_CLOSED_FOLDERS).evaluate(destination) == AccessDecisionVoter.ACCESS_GRANTED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
if (capabilityService.getCapability(RMPermissionModel.CREATE_MODIFY_RECORDS_IN_CUTOFF_FOLDERS).evaluate(destination) == AccessDecisionVoter.ACCESS_GRANTED)
if (capabilityService.getCapability(CREATE_MODIFY_RECORDS_IN_CUTOFF_FOLDERS).evaluate(destination) == AccessDecisionVoter.ACCESS_GRANTED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
if (capabilityService.getCapability(RMPermissionModel.CREATE_MODIFY_DESTROY_FILEPLAN_METADATA).evaluate(destination) == AccessDecisionVoter.ACCESS_GRANTED)
if (capabilityService.getCapability(CREATE_MODIFY_DESTROY_FILEPLAN_METADATA).evaluate(destination) == AccessDecisionVoter.ACCESS_GRANTED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
if (capabilityService.getCapability(RMPermissionModel.CREATE_HOLD).evaluate(destination) == AccessDecisionVoter.ACCESS_GRANTED)
if (capabilityService.getCapability(CREATE_HOLD).evaluate(destination) == AccessDecisionVoter.ACCESS_GRANTED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
if (((ChangeOrDeleteReferencesCapability)capabilityService.getCapability(RMPermissionModel.CHANGE_OR_DELETE_REFERENCES)).evaluate(destination, linkee) == AccessDecisionVoter.ACCESS_GRANTED)
if (((ChangeOrDeleteReferencesCapability)capabilityService.getCapability(CHANGE_OR_DELETE_REFERENCES)).evaluate(destination, linkee) == AccessDecisionVoter.ACCESS_GRANTED)
{
return AccessDecisionVoter.ACCESS_GRANTED;
}

View File

@@ -28,6 +28,7 @@
package org.alfresco.module.org_alfresco_module_rm.capability.policy;
import org.alfresco.module.org_alfresco_module_rm.capability.impl.CreateCapability;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QName;
import org.aopalliance.intercept.MethodInvocation;
@@ -42,10 +43,18 @@ public class CreatePolicy extends AbstractBasePolicy
{
NodeRef linkee = null;
QName assocType = null;
QName recordType = null;
// get the destination node
NodeRef destination = getTestNode(invocation, params, cad.getParameters().get(0), cad.isParent());
//get the recordType
for (Object qname : invocation.getArguments()) {
if (qname != null && (qname.equals(RecordsManagementModel.TYPE_RECORD_FOLDER) || qname.equals(RecordsManagementModel.TYPE_RECORD_CATEGORY))) {
recordType = (QName) qname;
}
}
if (cad.getParameters().size() > 1)
{
// get the linkee when present
@@ -58,7 +67,7 @@ public class CreatePolicy extends AbstractBasePolicy
}
}
return ((CreateCapability) getCapabilityService().getCapability("Create")).evaluate(destination, linkee, assocType);
return ((CreateCapability) getCapabilityService().getCapability("Create")).evaluate(destination, linkee, assocType, recordType);
}
}

View File

@@ -59,6 +59,9 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.rest.framework.core.exceptions.ConstraintViolatedException;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -198,7 +201,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
/**
* Behavior to initialize the disposition schedule of a newly filed record.
*
* @see org.alfresco.module.org_alfresco_module_rm.RecordsManagementPolicies.OnFileRecord#onFileRecord(org.alfresco.service.cmr.repository.NodeRef)
* @see RecordsManagementPolicies.OnFileRecord#onFileRecord(NodeRef)
*/
@Override
@Behaviour(kind=BehaviourKind.CLASS, type="rma:record")
@@ -216,7 +219,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#refreshDispositionAction(NodeRef)
* @see DispositionService#refreshDispositionAction(NodeRef)
*/
@Override
public void refreshDispositionAction(NodeRef nodeRef)
@@ -242,7 +245,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
/** ========= Disposition Property Methods ========= */
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#registerDispositionProperty(org.alfresco.module.org_alfresco_module_rm.disposition.property.DispositionProperty)
* @see DispositionService#registerDispositionProperty(DispositionProperty)
*/
@Override
public void registerDispositionProperty(DispositionProperty dispositionProperty)
@@ -251,7 +254,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getDispositionProperties(boolean, java.lang.String)
* @see DispositionService#getDispositionProperties(boolean, String)
*/
@Override
public Collection<DispositionProperty> getDispositionProperties(boolean isRecordLevel, String dispositionAction)
@@ -270,7 +273,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getDispositionProperties()
* @see DispositionService#getDispositionProperties()
*/
@Override
public Collection<DispositionProperty> getDispositionProperties()
@@ -281,12 +284,11 @@ public class DispositionServiceImpl extends ServiceBaseImpl
/** ========= Disposition Schedule Methods ========= */
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getDispositionSchedule(org.alfresco.service.cmr.repository.NodeRef)
* @see DispositionService#getDispositionSchedule(NodeRef)
*/
@Override
public DispositionSchedule getDispositionSchedule(final NodeRef nodeRef)
{
DispositionSchedule ds = null;
NodeRef dsNodeRef = null;
if (isRecord(nodeRef))
{
@@ -311,36 +313,33 @@ public class DispositionServiceImpl extends ServiceBaseImpl
if (dsNextAction != null)
{
final NodeRef action = dsNextAction.getNextActionNodeRef();
if (isNotTrue((Boolean)nodeService.getProperty(action, PROP_MANUALLY_SET_AS_OF)))
if (isNotTrue((Boolean)nodeService.getProperty(action, PROP_MANUALLY_SET_AS_OF)) && !dsNextAction.getWriteMode().equals(WriteMode.READ_ONLY))
{
if (!dsNextAction.getWriteMode().equals(WriteMode.READ_ONLY))
final String dispositionActionName = dsNextAction.getNextActionName();
final Date dispositionActionDate = dsNextAction.getNextActionDateAsOf();
RunAsWork<Void> runAsWork = () -> {
nodeService.setProperty(action, PROP_DISPOSITION_AS_OF, dispositionActionDate);
return null;
};
// if the current transaction is READ ONLY set the property on the node
// in a READ WRITE transaction
if (AlfrescoTransactionSupport.getTransactionReadState().equals(TxnReadState.TXN_READ_ONLY))
{
final String dispositionActionName = dsNextAction.getNextActionName();
final Date dispositionActionDate = dsNextAction.getNextActionDateAsOf();
RunAsWork<Void> runAsWork = () -> {
nodeService.setProperty(action, PROP_DISPOSITION_AS_OF, dispositionActionDate);
return null;
};
// if the current transaction is READ ONLY set the property on the node
// in a READ WRITE transaction
if (AlfrescoTransactionSupport.getTransactionReadState().equals(TxnReadState.TXN_READ_ONLY))
{
transactionService.getRetryingTransactionHelper().doInTransaction((RetryingTransactionCallback<Void>) () -> {
AuthenticationUtil.runAsSystem(runAsWork);
return null;
}, false, true);
}
else
{
transactionService.getRetryingTransactionHelper().doInTransaction((RetryingTransactionCallback<Void>) () -> {
AuthenticationUtil.runAsSystem(runAsWork);
}
return null;
}, false, true);
}
else
{
AuthenticationUtil.runAsSystem(runAsWork);
}
if (dsNextAction.getWriteMode().equals(WriteMode.DATE_AND_NAME))
{
nodeService.setProperty(action, PROP_DISPOSITION_ACTION_NAME, dispositionActionName);
}
if (dsNextAction.getWriteMode().equals(WriteMode.DATE_AND_NAME))
{
nodeService.setProperty(action, PROP_DISPOSITION_ACTION_NAME, dispositionActionName);
}
}
@@ -352,7 +351,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
// Get the disposition instructions for the node reference provided
dsNodeRef = getDispositionScheduleImpl(nodeRef);
}
DispositionSchedule ds = null;
if (dsNodeRef != null)
{
ds = new DispositionScheduleImpl(serviceRegistry, nodeService, dsNodeRef);
@@ -382,7 +381,8 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
return result;
}
@Override
public DispositionSchedule getOriginDispositionSchedule(NodeRef nodeRef)
{
NodeRef parent = this.nodeService.getPrimaryParent(nodeRef).getParentRef();
@@ -406,7 +406,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getAssociatedDispositionSchedule(org.alfresco.service.cmr.repository.NodeRef)
* @see DispositionService#getAssociatedDispositionSchedule(NodeRef)
*/
@Override
public DispositionSchedule getAssociatedDispositionSchedule(NodeRef nodeRef)
@@ -437,7 +437,6 @@ public class DispositionServiceImpl extends ServiceBaseImpl
*/
private NodeRef getAssociatedDispositionScheduleImpl(NodeRef nodeRef)
{
NodeRef result = null;
ParameterCheck.mandatory("nodeRef", nodeRef);
// Make sure we are dealing with an RM node
@@ -445,6 +444,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
{
throw new AlfrescoRuntimeException("Can not find the associated retention schedule for a non records management component. (nodeRef=" + nodeRef.toString() + ")");
}
NodeRef result = null;
if (getInternalNodeService().hasAspect(nodeRef, ASPECT_SCHEDULED))
{
List<ChildAssociationRef> childAssocs = getInternalNodeService().getChildAssocs(nodeRef, ASSOC_DISPOSITION_SCHEDULE, RegexQNamePattern.MATCH_ALL);
@@ -459,7 +459,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getAssociatedRecordsManagementContainer(org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule)
* @see DispositionService#getAssociatedRecordsManagementContainer(DispositionSchedule)
*/
@Override
public NodeRef getAssociatedRecordsManagementContainer(DispositionSchedule dispositionSchedule)
@@ -477,12 +477,9 @@ public class DispositionServiceImpl extends ServiceBaseImpl
{
// TODO in the future we should be able to support disposition schedule reuse, but for now just warn that
// only the first disposition schedule will be considered
if (LOGGER.isWarnEnabled())
{
LOGGER.warn("Retention schedule has more than one associated records management container. " +
"This is not currently supported so only the first container will be considered. " +
"(dispositionScheduleNodeRef=" + dispositionSchedule.getNodeRef().toString() + ")");
}
LOGGER.atWarn().log("Retention schedule has more than one associated records management container. " +
"This is not currently supported so only the first container will be considered. " +
"(dispositionScheduleNodeRef={})", dispositionSchedule.getNodeRef());
}
// Get the container reference
@@ -495,7 +492,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#hasDisposableItems(org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule)
* @see DispositionService#hasDisposableItems(DispositionSchedule)
*/
@Override
public boolean hasDisposableItems(DispositionSchedule dispositionSchdule)
@@ -537,19 +534,16 @@ public class DispositionServiceImpl extends ServiceBaseImpl
return true;
}
}
else if (filePlanService.isRecordCategory(item) && getAssociatedDispositionScheduleImpl(item) == null)
else if (filePlanService.isRecordCategory(item) && getAssociatedDispositionScheduleImpl(item) == null && hasDisposableItemsImpl(isRecordLevelDisposition, item))
{
if (hasDisposableItemsImpl(isRecordLevelDisposition, item));
{
return true;
}
return true;
}
}
return false;
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getDisposableItems(org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule)
* @see DispositionService#getDisposableItems(DispositionSchedule)
*/
@Override
public List<NodeRef> getDisposableItems(DispositionSchedule dispositionSchedule)
@@ -564,7 +558,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#isDisposableItem(org.alfresco.service.cmr.repository.NodeRef)
* @see DispositionService#isDisposableItem(NodeRef)
*/
@Override
public boolean isDisposableItem(NodeRef nodeRef)
@@ -604,20 +598,18 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#createDispositionSchedule(org.alfresco.service.cmr.repository.NodeRef, java.util.Map)
* @see DispositionService#createDispositionSchedule(NodeRef, Map)
*/
@Override
public DispositionSchedule createDispositionSchedule(NodeRef nodeRef, Map<QName, Serializable> props)
{
NodeRef dsNodeRef = null;
// Check mandatory parameters
ParameterCheck.mandatory("nodeRef", nodeRef);
// Check exists
if (!nodeService.exists(nodeRef))
{
throw new AlfrescoRuntimeException("Unable to create retention schedule, because node does not exist. (nodeRef=" + nodeRef.toString() + ")");
throw new EntityNotFoundException(nodeRef.getId());
}
// Check is sub-type of rm:recordCategory
@@ -625,10 +617,12 @@ public class DispositionServiceImpl extends ServiceBaseImpl
if (!TYPE_RECORD_CATEGORY.equals(nodeRefType) &&
!dictionaryService.isSubClass(nodeRefType, TYPE_RECORD_CATEGORY))
{
throw new AlfrescoRuntimeException("Unable to create retention schedule on a node that is not a records management container.");
throw new InvalidArgumentException("The given id:'" + nodeRef.getId() + "' (nodeType:" + nodeRef
+ ") is not valid. Expected nodeType is:" + TYPE_RECORD_CATEGORY);
}
behaviourFilter.disableBehaviour(nodeRef, ASPECT_SCHEDULED);
NodeRef dsNodeRef = null;
try
{
// Add the schedules aspect if required
@@ -662,7 +656,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
else
{
// Error since the node already has a disposition schedule set
throw new AlfrescoRuntimeException("Unable to create retention schedule on node that already has a retention schedule.");
throw new ConstraintViolatedException("Unable to create retention schedule on node that already has a retention schedule.");
}
}
finally
@@ -686,7 +680,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
{
// make sure at least a name has been defined
String name = (String)actionDefinitionParams.get(PROP_DISPOSITION_ACTION_NAME);
if (name == null || name.length() == 0)
if (name == null || name.isEmpty())
{
throw new IllegalArgumentException("'name' parameter is mandatory when creating a disposition action definition");
}
@@ -695,10 +689,10 @@ public class DispositionServiceImpl extends ServiceBaseImpl
// create the child association from the schedule to the action definition
NodeRef actionNodeRef = this.nodeService.createNode(schedule.getNodeRef(),
RecordsManagementModel.ASSOC_DISPOSITION_ACTION_DEFINITIONS,
ASSOC_DISPOSITION_ACTION_DEFINITIONS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
QName.createValidLocalName(name)),
RecordsManagementModel.TYPE_DISPOSITION_ACTION_DEFINITION, actionDefinitionParams).getChildRef();
TYPE_DISPOSITION_ACTION_DEFINITION, actionDefinitionParams).getChildRef();
// get the updated disposition schedule and retrieve the new action definition
NodeRef scheduleParent = this.nodeService.getPrimaryParent(schedule.getNodeRef()).getParentRef();
@@ -707,7 +701,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#removeDispositionActionDefinition(org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule, org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition)
* @see DispositionService#removeDispositionActionDefinition(DispositionSchedule, DispositionActionDefinition)
*/
@Override
public void removeDispositionActionDefinition(DispositionSchedule schedule, DispositionActionDefinition actionDefinition)
@@ -777,16 +771,12 @@ public class DispositionServiceImpl extends ServiceBaseImpl
DispositionAction da;
// check if current transaction is a READ ONLY one and if true create the node in a READ WRITE transaction
if (AlfrescoTransactionSupport.getTransactionReadState().equals(TxnReadState.TXN_READ_ONLY))
{
da =
transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<DispositionAction>()
{
public DispositionAction execute() throws Throwable
{
return createDispositionAction(nodeRef, props);
}
}, false, true);
if (AlfrescoTransactionSupport.getTransactionReadState().equals(TxnReadState.TXN_READ_ONLY)) {
da = transactionService.getRetryingTransactionHelper().doInTransaction(
() -> createDispositionAction(nodeRef, props),
false,
true
);
}
else
{
@@ -836,13 +826,13 @@ public class DispositionServiceImpl extends ServiceBaseImpl
Period period = dispositionActionDefinition.getPeriod();
if (period != null)
{
Date contextDate = null;
Date contextDate;
// Get the period properties value
QName periodProperty = dispositionActionDefinition.getPeriodProperty();
if (periodProperty != null)
{
if (RecordsManagementModel.PROP_DISPOSITION_AS_OF.equals(periodProperty))
if (PROP_DISPOSITION_AS_OF.equals(periodProperty))
{
DispositionAction lastCompletedDispositionAction = getLastCompletedDispostionAction(nodeRef);
if (lastCompletedDispositionAction != null)
@@ -886,7 +876,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#isNextDispositionActionEligible(org.alfresco.service.cmr.repository.NodeRef)
* @see DispositionService#isNextDispositionActionEligible(NodeRef)
*/
@Override
public boolean isNextDispositionActionEligible(NodeRef nodeRef)
@@ -940,7 +930,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
{
NodeRef eventExecution = assoc.getChildRef();
Boolean isCompleteValue = (Boolean) getInternalNodeService().getProperty(eventExecution, PROP_EVENT_EXECUTION_COMPLETE);
boolean isComplete = false;
boolean isComplete;
if (isCompleteValue != null)
{
isComplete = isCompleteValue.booleanValue();
@@ -987,7 +977,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getNextDispositionAction(org.alfresco.service.cmr.repository.NodeRef)
* @see DispositionService#getNextDispositionAction(NodeRef)
*/
@Override
public DispositionAction getNextDispositionAction(NodeRef nodeRef)
@@ -1006,7 +996,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
/** ========= Disposition Action History Methods ========= */
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getCompletedDispositionActions(org.alfresco.service.cmr.repository.NodeRef)
* @see DispositionService#getCompletedDispositionActions(NodeRef)
*/
@Override
public List<DispositionAction> getCompletedDispositionActions(NodeRef nodeRef)
@@ -1022,7 +1012,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#getLastCompletedDispostionAction(org.alfresco.service.cmr.repository.NodeRef)
* @see DispositionService#getLastCompletedDispostionAction(NodeRef)
*/
@Override
public DispositionAction getLastCompletedDispostionAction(NodeRef nodeRef)
@@ -1038,7 +1028,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#isDisposableItemCutoff(NodeRef)
* @see DispositionService#isDisposableItemCutoff(NodeRef)
*/
@Override
public boolean isDisposableItemCutoff(NodeRef nodeRef)
@@ -1048,7 +1038,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#updateNextDispositionAction(NodeRef)
* @see DispositionService#updateNextDispositionAction(NodeRef)
*/
@Override
public void updateNextDispositionAction(final NodeRef nodeRef)
@@ -1058,7 +1048,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
RunAsWork<Void> runAsWork = new RunAsWork<Void>()
{
/**
* @see org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork#doWork()
* @see RunAsWork#doWork()
*/
@Override
public Void doWork()
@@ -1077,7 +1067,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#updateNextDispositionAction(NodeRef)
* @see DispositionService#updateNextDispositionAction(NodeRef)
*/
@Override
public void updateNextDispositionAction(final NodeRef nodeRef, final DispositionSchedule dispositionSchedule)
@@ -1087,7 +1077,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
RunAsWork<Void> runAsWork = new RunAsWork<Void>()
{
/**
* @see org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork#doWork()
* @see RunAsWork#doWork()
*/
@Override
public Void doWork()
@@ -1113,16 +1103,13 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
List<DispositionActionDefinition> dispositionActionDefinitions = dispositionSchedule.getDispositionActionDefinitions();
DispositionActionDefinition currentDispositionActionDefinition = null;
DispositionActionDefinition currentDispositionActionDefinition;
DispositionActionDefinition nextDispositionActionDefinition = null;
if (currentDispositionAction == null)
if (currentDispositionAction == null && !dispositionActionDefinitions.isEmpty())
{
if (!dispositionActionDefinitions.isEmpty())
{
// The next disposition action is the first action
nextDispositionActionDefinition = dispositionActionDefinitions.get(0);
}
// The next disposition action is the first action
nextDispositionActionDefinition = dispositionActionDefinitions.get(0);
}
else
{
@@ -1167,7 +1154,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService#cutoffDisposableItem(NodeRef)
* @see DispositionService#cutoffDisposableItem(NodeRef)
*/
@Override
public void cutoffDisposableItem(final NodeRef nodeRef)
@@ -1205,6 +1192,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
// runAs system so that we can close a record that has already been cutoff
authenticationUtil.runAsSystem(new RunAsWork<Void>()
{
@Override
public Void doWork() throws Exception
{
recordFolderService.closeRecordFolder(nodeRef);
@@ -1224,6 +1212,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
}
@Override
public Date getDispositionActionDate(NodeRef record, NodeRef dispositionSchedule, String dispositionActionName)
{
DispositionSchedule ds = new DispositionScheduleImpl(serviceRegistry, nodeService, dispositionSchedule);
@@ -1243,7 +1232,8 @@ public class DispositionServiceImpl extends ServiceBaseImpl
}
return null;
}
@Override
public void recalculateNextDispositionStep(NodeRef record)
{
List<NodeRef> recordFolders = recordFolderService.getRecordFolders(record);
@@ -1384,14 +1374,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
Date calculatedDate = (nextDispositionActionDate != null ? nextDispositionActionDate : maxDate);
// We only need to update the date if the current one is too early.
if (recordDate.before(calculatedDate))
{
return WriteMode.DATE_ONLY;
}
else
{
return WriteMode.READ_ONLY;
}
return recordDate.before(calculatedDate) ? WriteMode.DATE_ONLY : WriteMode.READ_ONLY;
}
/**
@@ -1414,7 +1397,7 @@ public class DispositionServiceImpl extends ServiceBaseImpl
DispositionSchedule ds = new DispositionScheduleImpl(serviceRegistry, nodeService, folderDS);
List<DispositionActionDefinition> dispositionActionDefinitions = ds.getDispositionActionDefinitions();
if (dispositionActionDefinitions != null && dispositionActionDefinitions.size() > 0)
if (dispositionActionDefinitions != null && !dispositionActionDefinitions.isEmpty())
{
DispositionActionDefinition firstDispositionActionDef = dispositionActionDefinitions.get(0);
dispositionNodeRef = folderDS;

View File

@@ -219,7 +219,7 @@ public class FilePlanServiceImpl extends ServiceBaseImpl
}
else
{
return rmContainerCacheManager.get(storeRef);
return new HashSet<>(rmContainerCacheManager.get(storeRef));
}
return results;

View File

@@ -111,6 +111,24 @@ public interface HoldService
*/
void setHoldReason(NodeRef hold, String reason);
/**
* Sets the reason for the hold deletion
*
* @param hold The {@link NodeRef} of the hold
* @param reason {@link String} The reason for the hold
*/
void setHoldDeletionReason(NodeRef hold, String reason);
/**
* Updates a hold with the given name, reason and description
*
* @param hold The {@link NodeRef} of the hold
* @param name {@link String} The name of the hold
* @param reason {@link String} The reason of the hold
* @param description {@link String} The description of the hold
*/
void updateHold(NodeRef hold, String name, String reason, String description);
/**
* Deletes the hold
*

View File

@@ -29,6 +29,7 @@ package org.alfresco.module.org_alfresco_module_rm.hold;
import static org.alfresco.model.ContentModel.ASPECT_LOCKABLE;
import static org.alfresco.model.ContentModel.ASSOC_CONTAINS;
import static org.alfresco.model.ContentModel.PROP_DESCRIPTION;
import static org.alfresco.model.ContentModel.PROP_NAME;
import java.io.Serializable;
@@ -458,11 +459,11 @@ public class HoldServiceImpl extends ServiceBaseImpl
// create map of properties
Map<QName, Serializable> properties = new HashMap<>(3);
properties.put(ContentModel.PROP_NAME, name);
properties.put(PROP_NAME, name);
properties.put(PROP_HOLD_REASON, reason);
if (description != null && !description.isEmpty())
{
properties.put(ContentModel.PROP_DESCRIPTION, description);
properties.put(PROP_DESCRIPTION, description);
}
// create assoc name
@@ -512,6 +513,39 @@ public class HoldServiceImpl extends ServiceBaseImpl
}
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.hold.HoldService#setHoldDeletionReason(org.alfresco.service.cmr.repository.NodeRef, java.lang.String)
*/
@Override
public void setHoldDeletionReason(NodeRef hold, String reason)
{
ParameterCheck.mandatory("hold", hold);
ParameterCheck.mandatory("reason", reason);
if (nodeService.exists(hold) && isHold(hold))
{
nodeService.setProperty(hold, PROP_HOLD_DELETION_REASON, reason);
}
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.hold.HoldService#updateHold(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.lang.String, java.lang.String) (org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public void updateHold(NodeRef hold, String name, String reason, String description)
{
ParameterCheck.mandatory("hold", hold);
ParameterCheck.mandatory("name", name);
ParameterCheck.mandatory("reason", reason);
if (nodeService.exists(hold) && isHold(hold))
{
nodeService.setProperty(hold, PROP_NAME, name);
nodeService.setProperty(hold, PROP_HOLD_REASON, reason);
nodeService.setProperty(hold, PROP_DESCRIPTION, description);
}
}
/**
* @see org.alfresco.module.org_alfresco_module_rm.hold.HoldService#deleteHold(org.alfresco.service.cmr.repository.NodeRef)
*/
@@ -563,7 +597,7 @@ public class HoldServiceImpl extends ServiceBaseImpl
if (permissionService.hasPermission(nodeRef, permission) == AccessStatus.DENIED)
{
heldNames.add((String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME));
heldNames.add((String) nodeService.getProperty(nodeRef, PROP_NAME));
}
}
catch (AccessDeniedException ade)
@@ -630,7 +664,7 @@ public class HoldServiceImpl extends ServiceBaseImpl
{
if (!isHold(hold))
{
final String holdName = (String) nodeService.getProperty(hold, ContentModel.PROP_NAME);
final String holdName = (String) nodeService.getProperty(hold, PROP_NAME);
throw new IntegrityException(I18NUtil.getMessage("rm.hold.not-hold", holdName), null);
}
@@ -688,7 +722,7 @@ public class HoldServiceImpl extends ServiceBaseImpl
{
if (!isRecordFolder(nodeRef) && !instanceOf(nodeRef, ContentModel.TYPE_CONTENT))
{
final String nodeName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
final String nodeName = (String) nodeService.getProperty(nodeRef, PROP_NAME);
throw new IntegrityException(I18NUtil.getMessage("rm.hold.add-to-hold-invalid-type", nodeName), null);
}
@@ -795,7 +829,7 @@ public class HoldServiceImpl extends ServiceBaseImpl
{
if (!isHold(hold))
{
final String holdName = (String) nodeService.getProperty(hold, ContentModel.PROP_NAME);
final String holdName = (String) nodeService.getProperty(hold, PROP_NAME);
throw new IntegrityException(I18NUtil.getMessage("rm.hold.not-hold", holdName), null);
}

View File

@@ -35,6 +35,7 @@ import org.alfresco.service.namespace.QName;
*
* @author Roy Wetherall
*/
@SuppressWarnings("PMD.ConstantsInInterface")
@AlfrescoPublicApi
public interface RecordsManagementModel extends RecordsManagementCustomModel
{
@@ -200,6 +201,7 @@ public interface RecordsManagementModel extends RecordsManagementCustomModel
// Hold type
QName TYPE_HOLD = QName.createQName(RM_URI, "hold");
QName PROP_HOLD_REASON = QName.createQName(RM_URI, "holdReason");
QName PROP_HOLD_DELETION_REASON = QName.createQName(RM_URI, "holdDeletionReason");
//since 3.2
@Deprecated
QName ASSOC_FROZEN_RECORDS = QName.createQName(RM_URI, "frozenRecords");

View File

@@ -0,0 +1,155 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.fileplans;
import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank;
import static org.alfresco.util.ParameterCheck.mandatory;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.rest.framework.WebApiDescription;
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.Parameters;
import org.alfresco.rm.rest.api.impl.ApiNodesModelFactory;
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
import org.alfresco.rm.rest.api.model.HoldModel;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.transaction.TransactionService;
import org.springframework.beans.factory.InitializingBean;
/**
* File plan holds relation
*
* @author Damian Ujma
*/
@RelationshipResource(name = "holds", entityResource = FilePlanEntityResource.class, title = "Holds in a file plan")
public class FilePlanHoldsRelation implements
RelationshipResourceAction.Create<HoldModel>,
RelationshipResourceAction.Read<HoldModel>,
InitializingBean
{
private FilePlanComponentsApiUtils apiUtils;
private ApiNodesModelFactory nodesModelFactory;
private HoldService holdService;
private FileFolderService fileFolderService;
private TransactionService transactionService;
@Override
public void afterPropertiesSet() throws Exception
{
mandatory("apiUtils", this.apiUtils);
mandatory("nodesModelFactory", this.nodesModelFactory);
mandatory("holdService", this.holdService);
mandatory("fileFolderService", this.fileFolderService);
mandatory("transactionService", this.transactionService);
}
@Override
@WebApiDescription(title = "Return a paged list of holds for the file plan identified by 'filePlanId'")
public CollectionWithPagingInfo<HoldModel> readAll(String filePlanId, Parameters parameters)
{
checkNotBlank("filePlanId", filePlanId);
mandatory("parameters", parameters);
NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(filePlanId, RecordsManagementModel.TYPE_FILE_PLAN);
List<NodeRef> holds = holdService.getHolds(parentNodeRef);
List<HoldModel> page = holds.stream()
.map(hold -> fileFolderService.getFileInfo(hold))
.map(nodesModelFactory::createHoldModel)
.skip(parameters.getPaging().getSkipCount())
.limit(parameters.getPaging().getMaxItems())
.collect(Collectors.toCollection(LinkedList::new));
int totalItems = holds.size();
boolean hasMore = parameters.getPaging().getSkipCount() + parameters.getPaging().getMaxItems() < totalItems;
return CollectionWithPagingInfo.asPaged(parameters.getPaging(), page, hasMore, totalItems);
}
@Override
@WebApiDescription(title = "Create one (or more) holds in a file plan identified by 'filePlanId'")
public List<HoldModel> create(String filePlanId, List<HoldModel> holds, Parameters parameters)
{
checkNotBlank("filePlanId", filePlanId);
mandatory("holds", holds);
mandatory("parameters", parameters);
NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(filePlanId, RecordsManagementModel.TYPE_FILE_PLAN);
RetryingTransactionCallback<List<NodeRef>> callback = () -> {
List<NodeRef> createdNodes = new LinkedList<>();
for (HoldModel nodeInfo : holds)
{
NodeRef newNodeRef = holdService.createHold(parentNodeRef, nodeInfo.name(), nodeInfo.reason(),
nodeInfo.description());
createdNodes.add(newNodeRef);
}
return createdNodes;
};
List<NodeRef> createdNodes = transactionService.getRetryingTransactionHelper()
.doInTransaction(callback, false, true);
return createdNodes.stream()
.map(hold -> fileFolderService.getFileInfo(hold))
.map(nodesModelFactory::createHoldModel)
.collect(Collectors.toCollection(LinkedList::new));
}
public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
{
this.apiUtils = apiUtils;
}
public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory)
{
this.nodesModelFactory = nodesModelFactory;
}
public void setHoldService(HoldService holdService)
{
this.holdService = holdService;
}
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
}

View File

@@ -0,0 +1,163 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.holds;
import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank;
import static org.alfresco.util.ParameterCheck.mandatory;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import jakarta.servlet.http.HttpServletResponse;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkCancellationRequest;
import org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkMonitor;
import org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkService;
import org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkStatusAndProcessDetails;
import org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkUtils;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.rest.framework.Operation;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.NotFoundException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
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.Parameters;
import org.alfresco.rest.framework.webscripts.WithResponse;
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
import org.alfresco.rm.rest.api.model.BulkCancellationEntry;
import org.alfresco.rm.rest.api.model.HoldBulkStatusEntry;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.springframework.extensions.surf.util.I18NUtil;
@RelationshipResource(name = "bulk-statuses", entityResource = HoldsEntityResource.class, title = "Bulk statuses of a hold")
public class HoldsBulkStatusesRelation
implements RelationshipResourceAction.Read<HoldBulkStatusEntry>,
RelationshipResourceAction.ReadById<HoldBulkStatusEntry>
{
private HoldBulkMonitor holdBulkMonitor;
private HoldBulkService holdBulkService;
private FilePlanComponentsApiUtils apiUtils;
private PermissionService permissionService;
@Override
public CollectionWithPagingInfo<HoldBulkStatusEntry> readAll(String holdId, Parameters parameters)
{
// validate parameters
checkNotBlank("holdId", holdId);
mandatory("parameters", parameters);
NodeRef holdRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
checkReadPermissions(holdRef);
List<HoldBulkStatusAndProcessDetails> statuses = holdBulkMonitor.getBulkStatusesWithProcessDetails(holdId);
List<HoldBulkStatusEntry> page = statuses.stream()
.map(HoldBulkUtils::toHoldBulkStatusEntry)
.skip(parameters.getPaging().getSkipCount())
.limit(parameters.getPaging().getMaxItems())
.collect(Collectors.toCollection(LinkedList::new));
int totalItems = statuses.size();
boolean hasMore = parameters.getPaging().getSkipCount() + parameters.getPaging().getMaxItems() < totalItems;
return CollectionWithPagingInfo.asPaged(parameters.getPaging(), page, hasMore, totalItems);
}
@Override
public HoldBulkStatusEntry readById(String holdId, String bulkStatusId, Parameters parameters)
throws RelationshipResourceNotFoundException
{
checkNotBlank("holdId", holdId);
checkNotBlank("bulkStatusId", bulkStatusId);
mandatory("parameters", parameters);
NodeRef holdRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
checkReadPermissions(holdRef);
return Optional.ofNullable(holdBulkMonitor.getBulkStatusWithProcessDetails(holdId, bulkStatusId))
.map(HoldBulkUtils::toHoldBulkStatusEntry)
.orElseThrow(() -> new EntityNotFoundException(bulkStatusId));
}
@Operation("cancel")
@WebApiDescription(title = "Cancel a bulk operation",
successStatus = HttpServletResponse.SC_OK)
public void cancelBulkOperation(String holdId, String bulkStatusId, BulkCancellationEntry bulkCancellationEntry,
Parameters parameters,
WithResponse withResponse)
{
checkNotBlank("holdId", holdId);
checkNotBlank("bulkStatusId", bulkStatusId);
mandatory("parameters", parameters);
NodeRef holdRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
checkReadPermissions(holdRef);
if (holdBulkMonitor.getBulkStatus(bulkStatusId) == null)
{
throw new NotFoundException("Bulk status not found");
}
holdBulkService.cancelBulkOperation(holdRef, bulkStatusId, new BulkCancellationRequest(bulkCancellationEntry.reason()));
}
private void checkReadPermissions(NodeRef holdRef)
{
if (permissionService.hasReadPermission(holdRef) == AccessStatus.DENIED)
{
throw new PermissionDeniedException(I18NUtil.getMessage("permissions.err_access_denied"));
}
}
public void setHoldBulkMonitor(HoldBulkMonitor holdBulkMonitor)
{
this.holdBulkMonitor = holdBulkMonitor;
}
public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
{
this.apiUtils = apiUtils;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
public void setHoldBulkService(HoldBulkService holdBulkService)
{
this.holdBulkService = holdBulkService;
}
}

View File

@@ -0,0 +1,207 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.holds;
import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank;
import static org.alfresco.util.ParameterCheck.mandatory;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.node.integrity.IntegrityException;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
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.Parameters;
import org.alfresco.rm.rest.api.impl.ApiNodesModelFactory;
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
import org.alfresco.rm.rest.api.model.HoldChild;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.transaction.TransactionService;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.extensions.surf.util.I18NUtil;
/**
* Hold children relation
*
* @author Damian Ujma
*/
@RelationshipResource(name = "children", entityResource = HoldsEntityResource.class, title = "Children of a hold")
public class HoldsChildrenRelation implements
RelationshipResourceAction.Create<HoldChild>,
RelationshipResourceAction.Read<HoldChild>,
RelationshipResourceAction.Delete,
InitializingBean
{
private HoldService holdService;
private FilePlanComponentsApiUtils apiUtils;
private ApiNodesModelFactory nodesModelFactory;
private TransactionService transactionService;
private FileFolderService fileFolderService;
private PermissionService permissionService;
@Override
public void afterPropertiesSet() throws Exception
{
mandatory("holdService", holdService);
mandatory("apiUtils", apiUtils);
mandatory("nodesModelFactory", nodesModelFactory);
mandatory("transactionService", transactionService);
mandatory("fileFolderService", fileFolderService);
}
@Override
@WebApiDescription(title = "Add one (or more) children as children of a hold identified by 'holdId'")
public List<HoldChild> create(String holdId, List<HoldChild> children, Parameters parameters)
{
// validate parameters
checkNotBlank("holdId", holdId);
mandatory("children", children);
mandatory("parameters", parameters);
NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
RetryingTransactionCallback<List<NodeRef>> callback = () -> {
List<NodeRef> createdNodes = children.stream()
.map(holdChild -> new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, holdChild.id()))
.collect(Collectors.toList());
try
{
holdService.addToHold(parentNodeRef, createdNodes);
}
catch (IntegrityException exception)
{
// Throw 400 Bad Request when a node with id 'holdId' is not a hold or a child cannot be added to a hold
throw new InvalidArgumentException(exception.getMsgId()).initCause(exception);
}
return createdNodes;
};
List<NodeRef> nodeInfos = transactionService.getRetryingTransactionHelper()
.doInTransaction(callback, false, true);
return nodeInfos.stream()
.map(nodeRef -> new HoldChild(nodeRef.getId()))
.collect(Collectors.toCollection(LinkedList::new));
}
@Override
@WebApiDescription(title = "Return a paged list of hold children for the hold identified by 'holdId'")
public CollectionWithPagingInfo<HoldChild> readAll(String holdId, Parameters parameters)
{
checkNotBlank("holdId", holdId);
mandatory("parameters", parameters);
NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
List<NodeRef> children = holdService.getHeld(parentNodeRef);
List<HoldChild> page = children.stream()
.map(NodeRef::getId)
.map(HoldChild::new)
.skip(parameters.getPaging().getSkipCount())
.limit(parameters.getPaging().getMaxItems())
.collect(Collectors.toCollection(LinkedList::new));
int totalItems = children.size();
boolean hasMore = parameters.getPaging().getSkipCount() + parameters.getPaging().getMaxItems() < totalItems;
return CollectionWithPagingInfo.asPaged(parameters.getPaging(), page, hasMore, totalItems);
}
@Override
@WebApiDescription(title = "Remove a child from a hold", description = "Remove a child with id 'childId' from a hold with id 'holdId'")
public void delete(String holdId, String childId, Parameters parameters)
{
checkNotBlank("holdId", holdId);
checkNotBlank("childId", childId);
mandatory("parameters", parameters);
NodeRef nodeRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
NodeRef childRef = apiUtils.lookupByPlaceholder(childId);
if (permissionService.hasReadPermission(childRef) == AccessStatus.DENIED)
{
throw new PermissionDeniedException(I18NUtil.getMessage("permissions.err_access_denied"));
}
RetryingTransactionCallback<List<NodeRef>> callback = () -> {
try
{
holdService.removeFromHold(nodeRef, childRef);
}
catch (IntegrityException exception)
{
// Throw 400 Bad Request when a node with id 'holdId' is not a hold
throw new InvalidArgumentException(exception.getMsgId()).initCause(exception);
}
return null;
};
transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true);
}
public void setHoldService(HoldService holdService)
{
this.holdService = holdService;
}
public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
{
this.apiUtils = apiUtils;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory)
{
this.nodesModelFactory = nodesModelFactory;
}
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
}

View File

@@ -0,0 +1,212 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.holds;
import static org.alfresco.module.org_alfresco_module_rm.util.RMParameterCheck.checkNotBlank;
import static org.alfresco.util.ParameterCheck.mandatory;
import jakarta.servlet.http.HttpServletResponse;
import org.alfresco.module.org_alfresco_module_rm.bulk.BulkOperation;
import org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkService;
import org.alfresco.module.org_alfresco_module_rm.hold.HoldService;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.rest.framework.Operation;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.WebApiParam;
import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.webscripts.WithResponse;
import org.alfresco.rm.rest.api.impl.ApiNodesModelFactory;
import org.alfresco.rm.rest.api.impl.FilePlanComponentsApiUtils;
import org.alfresco.rm.rest.api.model.HoldBulkOperation;
import org.alfresco.rm.rest.api.model.HoldBulkOperationEntry;
import org.alfresco.module.org_alfresco_module_rm.bulk.hold.HoldBulkStatus;
import org.alfresco.rm.rest.api.model.HoldDeletionReason;
import org.alfresco.rm.rest.api.model.HoldModel;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.transaction.TransactionService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
/**
* Hold entity resource
*
* @author Damian Ujma
*/
@EntityResource(name = "holds", title = "Holds")
public class HoldsEntityResource implements
EntityResourceAction.ReadById<HoldModel>,
EntityResourceAction.Update<HoldModel>,
EntityResourceAction.Delete,
InitializingBean
{
private FilePlanComponentsApiUtils apiUtils;
private FileFolderService fileFolderService;
private ApiNodesModelFactory nodesModelFactory;
private HoldService holdService;
private TransactionService transactionService;
private HoldBulkService holdBulkService;
@Override
public void afterPropertiesSet() throws Exception
{
mandatory("nodesModelFactory", nodesModelFactory);
mandatory("apiUtils", apiUtils);
mandatory("fileFolderService", fileFolderService);
mandatory("holdService", holdService);
mandatory("transactionService", transactionService);
}
@Override
@WebApiDescription(title = "Get hold information", description = "Get information for a hold with id 'holdId'")
@WebApiParam(name = "holdId", title = "The hold id")
public HoldModel readById(String holdId, Parameters parameters)
{
checkNotBlank("holdId", holdId);
mandatory("parameters", parameters);
NodeRef hold = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
FileInfo info = fileFolderService.getFileInfo(hold);
return nodesModelFactory.createHoldModel(info);
}
@Override
@WebApiDescription(title = "Update a hold", description = "Updates a hold with id 'holdId'")
public HoldModel update(String holdId, HoldModel holdModel, Parameters parameters)
{
checkNotBlank("holdId", holdId);
mandatory("holdModel", holdModel);
mandatory("holdModel.name", holdModel.name());
mandatory("holdModel.reason", holdModel.reason());
mandatory("parameters", parameters);
NodeRef nodeRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
RetryingTransactionCallback<Void> callback = () -> {
holdService.updateHold(nodeRef, holdModel.name(), holdModel.reason(), holdModel.description());
return null;
};
transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true);
RetryingTransactionCallback<FileInfo> readCallback = () -> fileFolderService.getFileInfo(nodeRef);
FileInfo info = transactionService.getRetryingTransactionHelper().doInTransaction(readCallback, false, true);
return nodesModelFactory.createHoldModel(info);
}
@Override
@WebApiDescription(title = "Delete hold", description = "Deletes a hold with id 'holdId'")
public void delete(String holdId, Parameters parameters)
{
checkNotBlank("holdId", holdId);
mandatory("parameters", parameters);
NodeRef hold = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
RetryingTransactionCallback<Void> callback = () -> {
holdService.deleteHold(hold);
return null;
};
transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true);
}
@Operation("delete")
@WebApiDescription(title = "Delete hold with a reason",
successStatus = HttpServletResponse.SC_OK)
public HoldDeletionReason deleteHoldWithReason(String holdId, HoldDeletionReason reason, Parameters parameters,
WithResponse withResponse)
{
checkNotBlank("holdId", holdId);
mandatory("reason", reason);
mandatory("parameters", parameters);
NodeRef hold = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
String deletionReason = reason.reason();
RetryingTransactionCallback<Void> callback = () -> {
if (StringUtils.isNotBlank(deletionReason))
{
holdService.setHoldDeletionReason(hold, deletionReason);
}
holdService.deleteHold(hold);
return null;
};
transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true);
return reason;
}
@Operation("bulk")
@WebApiDescription(title = "Start the hold bulk operation",
successStatus = HttpServletResponse.SC_ACCEPTED)
public HoldBulkOperationEntry bulk(String holdId, HoldBulkOperation holdBulkOperation, Parameters parameters,
WithResponse withResponse)
{
// validate parameters
checkNotBlank("holdId", holdId);
mandatory("parameters", parameters);
NodeRef parentNodeRef = apiUtils.lookupAndValidateNodeType(holdId, RecordsManagementModel.TYPE_HOLD);
HoldBulkStatus holdBulkStatus = holdBulkService.execute(parentNodeRef,
new BulkOperation(holdBulkOperation.query(), holdBulkOperation.op().name()));
return new HoldBulkOperationEntry(holdBulkStatus.bulkStatusId(), holdBulkStatus.totalItems());
}
public void setApiUtils(FilePlanComponentsApiUtils apiUtils)
{
this.apiUtils = apiUtils;
}
public void setFileFolderService(FileFolderService fileFolderService)
{
this.fileFolderService = fileFolderService;
}
public void setNodesModelFactory(ApiNodesModelFactory nodesModelFactory)
{
this.nodesModelFactory = nodesModelFactory;
}
public void setHoldService(HoldService holdService)
{
this.holdService = holdService;
}
public void setTransactionService(TransactionService transactionService)
{
this.transactionService = transactionService;
}
public void setHoldBulkService(HoldBulkService holdBulkService)
{
this.holdBulkService = holdBulkService;
}
}

View File

@@ -0,0 +1,36 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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 info that defines the Information Governance Holds REST API
*
* @author Damian Ujma
*/
@WebApi(name="gs", scope=Api.SCOPE.PUBLIC, version=1)
package org.alfresco.rm.rest.api.holds;
import org.alfresco.rest.framework.Api;
import org.alfresco.rest.framework.WebApi;

View File

@@ -34,10 +34,16 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.alfresco.model.ContentModel;
import org.alfresco.module.org_alfresco_module_rm.RecordsManagementServiceRegistry;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinition;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionActionDefinitionImpl;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionSchedule;
import org.alfresco.module.org_alfresco_module_rm.disposition.DispositionService;
import org.alfresco.module.org_alfresco_module_rm.event.RecordsManagementEvent;
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.AssocChild;
@@ -47,11 +53,14 @@ import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.framework.jacksonextensions.BeanPropertiesFilter;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rm.rest.api.model.FilePlan;
import org.alfresco.rm.rest.api.model.HoldModel;
import org.alfresco.rm.rest.api.model.RMNode;
import org.alfresco.rm.rest.api.model.Record;
import org.alfresco.rm.rest.api.model.RecordCategory;
import org.alfresco.rm.rest.api.model.RecordCategoryChild;
import org.alfresco.rm.rest.api.model.RecordFolder;
import org.alfresco.rm.rest.api.model.RetentionPeriod;
import org.alfresco.rm.rest.api.model.RetentionSteps;
import org.alfresco.rm.rest.api.model.Transfer;
import org.alfresco.rm.rest.api.model.TransferChild;
import org.alfresco.rm.rest.api.model.TransferContainer;
@@ -60,6 +69,8 @@ import org.alfresco.rm.rest.api.model.UnfiledContainer;
import org.alfresco.rm.rest.api.model.UnfiledContainerChild;
import org.alfresco.rm.rest.api.model.UnfiledRecordFolder;
import org.alfresco.rm.rest.api.model.UnfiledRecordFolderChild;
import org.alfresco.rm.rest.api.model.RetentionSchedule;
import org.alfresco.rm.rest.api.model.RetentionScheduleActionDefinition;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.model.FileInfo;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
@@ -69,6 +80,9 @@ import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility class containing Alfresco and RM java services required by the API
@@ -80,6 +94,9 @@ import org.alfresco.service.namespace.QName;
public class ApiNodesModelFactory
{
/** Logger */
private static final Logger LOGGER = LoggerFactory.getLogger(ApiNodesModelFactory.class);
// excluded namespaces (aspects, properties, assoc types)
public static final List<String> EXCLUDED_NS = Arrays.asList(NamespaceService.SYSTEM_MODEL_1_0_URI);
@@ -101,6 +118,7 @@ public class ApiNodesModelFactory
private PersonService personService;
private DispositionService dispositionService;
private ServiceRegistry serviceRegistry;
private RecordsManagementServiceRegistry services;
public NodeService getNodeService()
{
@@ -152,6 +170,11 @@ public class ApiNodesModelFactory
this.serviceRegistry = serviceRegistry;
}
public void setRecordsManagementServiceRegistry(RecordsManagementServiceRegistry services)
{
this.services = services;
}
/**
* Helper method that sets the basic information for most of the node types.
*
@@ -503,15 +526,15 @@ public class ApiNodesModelFactory
}
if(RecordsManagementModel.TYPE_RECORD_FOLDER.equals(info.getType()))
{
if((!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_FOLDER)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_FOLDER)))
if (isRecordFolder(isMinimalInfo, propertyFilter, includeParam))
{
recordCategoryChild.setIsRecordFolder(true);
}
if((!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY)))
if (isRecordCategory(isMinimalInfo, propertyFilter, includeParam))
{
recordCategoryChild.setIsRecordCategory(false);
}
if((!isMinimalInfo && propertyFilter.isAllowed(RMNode.PARAM_IS_CLOSED)) || (isMinimalInfo && includeParam.contains(RMNode.PARAM_IS_CLOSED)))
if (isRecordCategoryChildClosed(isMinimalInfo, propertyFilter, includeParam))
{
recordCategoryChild.setIsClosed((Boolean) nodeService.getProperty(info.getNodeRef(), RecordsManagementModel.PROP_IS_CLOSED));
}
@@ -522,11 +545,11 @@ public class ApiNodesModelFactory
}
else
{
if((!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_FOLDER)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_FOLDER)))
if (isRecordFolder(isMinimalInfo, propertyFilter, includeParam))
{
recordCategoryChild.setIsRecordFolder(false);
}
if((!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY)))
if (isRecordCategory(isMinimalInfo, propertyFilter, includeParam))
{
recordCategoryChild.setIsRecordCategory(true);
}
@@ -535,13 +558,28 @@ public class ApiNodesModelFactory
DispositionSchedule ds = dispositionService.getDispositionSchedule(info.getNodeRef());
recordCategoryChild.setHasRetentionSchedule(ds != null);
}
if((!isMinimalInfo && propertyFilter.isAllowed(RMNode.PARAM_IS_CLOSED)) || (isMinimalInfo && includeParam.contains(RMNode.PARAM_IS_CLOSED)))
if (isRecordCategoryChildClosed(isMinimalInfo, propertyFilter, includeParam))
{
recordCategoryChild.setIsClosed(null);
}
}
}
private boolean isRecordCategoryChildClosed(boolean isMinimalInfo, BeanPropertiesFilter propertyFilter, List<String> includeParam)
{
return (!isMinimalInfo && propertyFilter.isAllowed(RMNode.PARAM_IS_CLOSED)) || (isMinimalInfo && includeParam.contains(RMNode.PARAM_IS_CLOSED));
}
private boolean isRecordCategory(boolean isMinimalInfo, BeanPropertiesFilter propertyFilter, List<String> includeParam)
{
return (!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY));
}
private boolean isRecordFolder(boolean isMinimalInfo, BeanPropertiesFilter propertyFilter, List<String> includeParam)
{
return (!isMinimalInfo && propertyFilter.isAllowed(RecordCategoryChild.PARAM_IS_RECORD_FOLDER)) || (isMinimalInfo && includeParam.contains(RecordCategoryChild.PARAM_IS_RECORD_FOLDER));
}
/**
* Utility method that maps record specific fields
@@ -564,7 +602,8 @@ public class ApiNodesModelFactory
{
Serializable val = info.getProperties().get(ContentModel.PROP_CONTENT);
if ((val != null) && (val instanceof ContentData)) {
if (val instanceof ContentData)
{
ContentData cd = (ContentData)val;
String mimeType = cd.getMimetype();
String mimeTypeName = serviceRegistry.getMimetypeService().getDisplaysByMimetype().get(mimeType);
@@ -637,6 +676,21 @@ public class ApiNodesModelFactory
}
}
/**
* Creates an object of type HoldModel
*
* @param info info of the hold
* @return HoldModel object
*/
public HoldModel createHoldModel(FileInfo info)
{
return new HoldModel(info.getNodeRef().getId(),
(String) info.getProperties().get(ContentModel.PROP_NAME),
(String) info.getProperties().get(ContentModel.PROP_DESCRIPTION),
(String) info.getProperties().get(RecordsManagementModel.PROP_HOLD_REASON));
}
/**
* Creates an object of type FilePlan
*
@@ -875,4 +929,238 @@ public class ApiNodesModelFactory
mapAssociations(record, info, parameters.getInclude());
return record;
}
}
/**
* Helper method that sets the information for the retention schedule type.
* @param dispositionSchedule
* @return RetentionSchedule
*/
public RetentionSchedule mapRetentionScheduleData(DispositionSchedule dispositionSchedule)
{
RetentionSchedule retentionSchedule = new RetentionSchedule();
retentionSchedule.setId(dispositionSchedule.getNodeRef().getId());
if (dispositionSchedule.getNodeRef() != null) {
NodeRef parent = this.nodeService.getPrimaryParent(dispositionSchedule.getNodeRef()).getParentRef();
retentionSchedule.setParentId(parent.getId());
}
retentionSchedule.setInstructions(dispositionSchedule.getDispositionInstructions());
retentionSchedule.setAuthority(dispositionSchedule.getDispositionAuthority());
retentionSchedule.setIsRecordLevel(dispositionSchedule.isRecordLevelDisposition());
boolean unpublishedUpdates = dispositionSchedule.getDispositionActionDefinitions().stream()
.map(DispositionActionDefinition::getNodeRef)
.anyMatch(actionDefNodeRef -> nodeService.hasAspect(actionDefNodeRef, RecordsManagementModel.ASPECT_UNPUBLISHED_UPDATE));
retentionSchedule.setUnpublishedUpdates(unpublishedUpdates);
return retentionSchedule;
}
/**
* Helper method that sets the information for the retention schedule action definition type.
* @param dispositionActionDefinition
* @return RetentionScheduleActionDefinition
*/
public RetentionScheduleActionDefinition mapRetentionScheduleActionDefData(DispositionActionDefinition dispositionActionDefinition)
{
RetentionScheduleActionDefinition retentionScheduleActionDefinition = new RetentionScheduleActionDefinition();
// Mapping basic properties
mapRetentionActionProperties(dispositionActionDefinition, retentionScheduleActionDefinition);
// Mapping period and period amount
mapPeriodProperties(dispositionActionDefinition, retentionScheduleActionDefinition);
// Mapping events properties
mapEventsProperties(dispositionActionDefinition, retentionScheduleActionDefinition);
return retentionScheduleActionDefinition;
}
/**
* Helper method that sets core information for the retention schedule action definition type.
* @param dispositionActionDefinition
* @param retentionScheduleActionDefinition
*/
private void mapRetentionActionProperties(DispositionActionDefinition dispositionActionDefinition, RetentionScheduleActionDefinition retentionScheduleActionDefinition)
{
retentionScheduleActionDefinition.setId(dispositionActionDefinition.getId());
retentionScheduleActionDefinition.setName(dispositionActionDefinition.getName());
retentionScheduleActionDefinition.setDescription(dispositionActionDefinition.getDescription());
retentionScheduleActionDefinition.setEligibleOnFirstCompleteEvent(dispositionActionDefinition.eligibleOnFirstCompleteEvent());
if (nodeService.getProperty(dispositionActionDefinition.getNodeRef(), RecordsManagementModel.PROP_COMBINE_DISPOSITION_STEP_CONDITIONS) != null)
{
retentionScheduleActionDefinition.setCombineRetentionStepConditions((Boolean) nodeService.getProperty(dispositionActionDefinition.getNodeRef(), RecordsManagementModel.PROP_COMBINE_DISPOSITION_STEP_CONDITIONS));
}
retentionScheduleActionDefinition.setLocation(dispositionActionDefinition.getLocation());
if (dispositionActionDefinition.getGhostOnDestroy() != null)
{
retentionScheduleActionDefinition.setRetainRecordMetadataAfterDestruction(dispositionActionDefinition.getGhostOnDestroy().equals("ghost"));
}
retentionScheduleActionDefinition.setIndex(dispositionActionDefinition.getIndex());
}
/**
* Helper method that sets the period-related information for the retention schedule action definition type.
* @param dispositionActionDefinition
* @param retentionScheduleActionDefinition
*/
private void mapPeriodProperties(DispositionActionDefinition dispositionActionDefinition, RetentionScheduleActionDefinition retentionScheduleActionDefinition)
{
if (dispositionActionDefinition.getPeriodProperty() != null)
{
retentionScheduleActionDefinition.setPeriodProperty(dispositionActionDefinition.getPeriodProperty().toPrefixString(namespaceService));
}
String period = dispositionActionDefinition.getPeriod().toString();
if (!period.isEmpty())
{
// In rest api we are splitting `period` property into `period` and `periodAmount`.
// so we need to split the period into two properties.
// ex. period -> 'month|10' so the split properties would be like below
// period -> 'month'
// periodAmount -> 10
String[] periodArray = period.split("\\|");
if (periodArray.length > 0)
{
retentionScheduleActionDefinition.setPeriod(periodArray[0]);
}
if (periodArray.length > 1)
{
try
{
retentionScheduleActionDefinition.setPeriodAmount(Integer.parseInt(periodArray[1]));
}
catch (NumberFormatException numberFormatException)
{
LOGGER.error("Error parsing period amount: {}{}", numberFormatException.getMessage(), periodArray[1], numberFormatException);
throw numberFormatException;
}
}
}
}
/**
* Helper method that sets the events information for the retention schedule action definition type.
* @param dispositionActionDefinition
* @param retentionScheduleActionDefinition
*/
private void mapEventsProperties(DispositionActionDefinition dispositionActionDefinition, RetentionScheduleActionDefinition retentionScheduleActionDefinition)
{
List<RecordsManagementEvent> events = dispositionActionDefinition.getEvents();
if (events != null && !events.isEmpty())
{
List<String> eventNames = events.stream()
.map(RecordsManagementEvent::getName)
.collect(Collectors.toList());
retentionScheduleActionDefinition.setEvents(eventNames);
}
}
/**
* Helper method that sets the optional information for the retention schedule type.
* @param retentionSchedule
* @param schedule
* @param includeParam
*/
public void mapRetentionScheduleOptionalInfo(RetentionSchedule retentionSchedule, DispositionSchedule schedule, List<String> includeParam)
{
if (includeParam != null && !includeParam.isEmpty() && includeParam.contains("actions"))
{
List<RetentionScheduleActionDefinition> actions = schedule.getDispositionActionDefinitions().stream()
.map(this::mapRetentionScheduleActionDefData)
.collect(Collectors.toList());
retentionSchedule.setActions(actions);
}
}
/**
* this method is used for creation of retention schedule action definition params
* @param nodeInfo retention schedule action definition
* @return Map<QName, Serializable>
*/
public Map<QName, Serializable> createRetentionActionDefinitionParams(RetentionScheduleActionDefinition nodeInfo)
{
Map<QName, Serializable> actionDefinitionParams= new HashMap<>();
String retentionActionName = nodeInfo.getName();
if (nodeInfo.getName().equals(RetentionSteps.DESTROY_NODE.stepName) ||
nodeInfo.getName().equals(RetentionSteps.DESTROY_CONTENT.stepName))
{
retentionActionName = "destroy";
}
actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_ACTION_NAME, retentionActionName);
actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_DESCRIPTION, nodeInfo.getDescription());
StringBuilder retentionPeriod = new StringBuilder(nodeInfo.getPeriod()).append("|");
if (isPeriodAmountApplicable(nodeInfo.getPeriod()))
{
retentionPeriod.append(nodeInfo.getPeriodAmount());
}
actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_PERIOD, retentionPeriod.toString());
QName periodProperty = QName.createQName(nodeInfo.getPeriodProperty(), namespaceService);
actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_PERIOD_PROPERTY, periodProperty);
actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_EVENT_COMBINATION,
nodeInfo.isEligibleOnFirstCompleteEvent());
boolean combineConditions = nodeInfo.getName().equals(RetentionSteps.ACCESSION.stepName) && nodeInfo.isCombineRetentionStepConditions();
actionDefinitionParams.put(RecordsManagementModel.PROP_COMBINE_DISPOSITION_STEP_CONDITIONS, combineConditions);
if(nodeInfo.getLocation() != null && nodeInfo.getName().equals(RetentionSteps.TRANSFER.stepName))
{
actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_LOCATION,
nodeInfo.getLocation());
}
List<String> inputEvents = nodeInfo.getEvents();
actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_EVENT, (Serializable) inputEvents);
if (RetentionSteps.DESTROY_CONTENT.stepName.equals(nodeInfo.getName()))
{
actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_ACTION_GHOST_ON_DESTROY, "ghost");
}
else if (RetentionSteps.DESTROY_NODE.stepName.equals(nodeInfo.getName()))
{
actionDefinitionParams.put(RecordsManagementModel.PROP_DISPOSITION_ACTION_GHOST_ON_DESTROY, "delete");
}
return actionDefinitionParams;
}
/**
* this method is used retrieve retention schedule action details
* @param retentionScheduleNodeRef nodeRef
* @return List<DispositionActionDefinition>
*/
public List<DispositionActionDefinition> getRetentionActions(NodeRef retentionScheduleNodeRef)
{
List<ChildAssociationRef> assocs = nodeService.getChildAssocs(
retentionScheduleNodeRef,
RecordsManagementModel.ASSOC_DISPOSITION_ACTION_DEFINITIONS,
RegexQNamePattern.MATCH_ALL);
// we are getting disposition action definitions based on retention schedule child association.
// setting the index value for each action.
List<DispositionActionDefinition> actions;
actions = IntStream.range(0, assocs.size())
.mapToObj(index ->
{
ChildAssociationRef assoc = assocs.get(index);
return new DispositionActionDefinitionImpl(
services.getRecordsManagementEventService(),
services.getRecordsManagementActionService(),
nodeService,
assoc.getChildRef(),
index);
})
.collect(Collectors.toList());
return actions;
}
/**
* this method is used to check period amount applicable or not for particular period
* @param period period
* @return boolean
*/
private boolean isPeriodAmountApplicable(String period)
{
// periodAmount property only applicable for following periods
// day, week, month, quarter, year and duration
return period.equals(RetentionPeriod.DAY.periodName) || period.equals(RetentionPeriod.MONTH.periodName) || period.equals(RetentionPeriod.QUARTER.periodName)
|| period.equals(RetentionPeriod.WEEK.periodName) || period.equals(RetentionPeriod.XML_DURATION.periodName) || period.equals(RetentionPeriod.YEAR.periodName);
}
}

View File

@@ -92,7 +92,7 @@ public class SearchTypesFactory
boolean includeRecords = false;
boolean includeSubTypes = false;
if (q != null)
if (q != null && q.getTree() != null)
{
// filtering via "where" clause
MapBasedQueryWalker propertyWalker = new MapBasedQueryWalker(listFolderChildrenEqualsQueryProperties, null);
@@ -101,11 +101,11 @@ public class SearchTypesFactory
Boolean isUnfiledRecordFolder = propertyWalker.getProperty(UnfiledChild.PARAM_IS_UNFILED_RECORD_FOLDER,
WhereClauseParser.EQUALS, Boolean.class);
Boolean isRecord = propertyWalker.getProperty(UnfiledChild.PARAM_IS_RECORD, WhereClauseParser.EQUALS, Boolean.class);
if ((isUnfiledRecordFolder != null && isUnfiledRecordFolder.booleanValue()) || (isRecord != null && !isRecord.booleanValue()))
if (checkIncludeUnfiledRecordFolders(isUnfiledRecordFolder, isRecord))
{
includeUnfiledRecordFolders = true;
}
else if ((isUnfiledRecordFolder != null && !isUnfiledRecordFolder.booleanValue()) || (isRecord != null && isRecord.booleanValue()))
else if (checkIncludeRecords(isUnfiledRecordFolder, isRecord))
{
includeRecords = true;
}
@@ -199,11 +199,11 @@ public class SearchTypesFactory
WhereClauseParser.EQUALS, Boolean.class);
Boolean isRecordCategory = propertyWalker.getProperty(RecordCategoryChild.PARAM_IS_RECORD_CATEGORY, WhereClauseParser.EQUALS, Boolean.class);
if ((isRecordFolder != null && isRecordFolder.booleanValue()) || (isRecordCategory != null && !isRecordCategory.booleanValue()))
if (checkIncludeUnfiledRecordFolders(isRecordFolder, isRecordCategory))
{
includeRecordFolders = true;
}
else if ((isRecordFolder != null && !isRecordFolder.booleanValue()) || (isRecordCategory != null && isRecordCategory.booleanValue()))
else if (checkIncludeRecords(isRecordFolder, isRecordCategory))
{
includeRecordCategories = true;
}
@@ -291,4 +291,16 @@ public class SearchTypesFactory
return new Pair<>(filterNodeTypeQName, filterIncludeSubTypes);
}
private static boolean checkIncludeRecords(Boolean isUnfiledRecordFolder, Boolean isRecord)
{
return (isUnfiledRecordFolder != null && !isUnfiledRecordFolder.booleanValue()) || (isRecord != null
&& isRecord.booleanValue());
}
private static boolean checkIncludeUnfiledRecordFolders(Boolean isUnfiledRecordFolder, Boolean isRecord)
{
return (isUnfiledRecordFolder != null && isUnfiledRecordFolder.booleanValue()) || (isRecord != null
&& !isRecord.booleanValue());
}
}

View File

@@ -0,0 +1,29 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.model;
public record BulkCancellationEntry(String reason) {}

View File

@@ -0,0 +1,33 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.alfresco.rest.api.search.model.Query;
public record HoldBulkOperation(@JsonProperty(required = true) Query query, @JsonProperty(required = true) HoldBulkOperationType op) {}

View File

@@ -0,0 +1,29 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.model;
public record HoldBulkOperationEntry(String bulkStatusId, long totalItems){}

View File

@@ -0,0 +1,38 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.model;
/**
* This enum represents the types of bulk operations that can be performed on holds
*/
public enum HoldBulkOperationType
{
/**
* The ADD operation represents adding items to a hold in bulk.
*/
ADD
}

View File

@@ -0,0 +1,33 @@
/*
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.model;
import java.util.Date;
public record HoldBulkStatusEntry(String bulkStatusId, Date startTime, Date endTime, long processedItems, long errorsCount,
long totalItems, String lastError, String status, String cancellationReason, HoldBulkOperation holdBulkOperation) {
}

View File

@@ -0,0 +1,36 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.model;
/**
* Hold Child POJO for use in the v1 REST API.
*
* @author Damian Ujma
*/
public record HoldChild(String id)
{
}

View File

@@ -0,0 +1,36 @@
/*-
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 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.rm.rest.api.model;
/**
* Hold Deletion Reason POJO for use in the v1 REST API.
*
* @author Damian Ujma
*/
public record HoldDeletionReason(String reason)
{
}

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