Compare commits

..

290 Commits

Author SHA1 Message Date
alfresco-build
23ccb397f4 [maven-release-plugin][skip ci] prepare release 20.127 2023-03-31 14:13:40 +00:00
Piotr Żurek
73ae0d0a6e ACS-4847 Remove Keycloak dependencies (#1848) 2023-03-31 15:28:14 +02:00
alfresco-build
f9b5e5a6fe [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-31 10:27:19 +00:00
alfresco-build
e5bfb0298d [maven-release-plugin][skip ci] prepare release 20.126 2023-03-31 10:27:16 +00:00
Piotr Żurek
34cb9bf76a ACS-4847 Bump AOS module (#1846) 2023-03-31 10:38:09 +02:00
alfresco-build
fcbd406170 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-30 12:26:47 +00:00
alfresco-build
730ab768e9 [maven-release-plugin][skip ci] prepare release 20.125 2023-03-30 12:26:43 +00:00
Kacper Magdziarz
fab591eb9b [ACS-4459] Investigate and extend/universalize current custom Solr mTLS implementation in Repository (#1735)
* ACS-4459 Add new HttpClient Factory for Mutual TLS and implement it for Transform Service
* ACS-4462 Add e2e for MTLS
2023-03-30 13:43:42 +02:00
alfresco-build
5bb96729fc [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-29 13:04:41 +00:00
alfresco-build
a80f2c4db7 [maven-release-plugin][skip ci] prepare release 20.124 2023-03-29 13:04:38 +00:00
Piotr Żurek
82df7ce5d4 ACS-4847 Expose authorization code and refresh token grant types for the AOS (#1836) 2023-03-29 14:16:08 +02:00
alfresco-build
73a1de37f6 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-29 11:22:30 +00:00
alfresco-build
63f9a8e142 [maven-release-plugin][skip ci] prepare release 20.123 2023-03-29 11:22:25 +00:00
rrajoria
f668ed9198 Updating webscript version 2023-03-29 15:33:18 +05:30
alfresco-build
ea15673116 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-29 08:46:12 +00:00
alfresco-build
6a2a298445 [maven-release-plugin][skip ci] prepare release 20.122 2023-03-29 08:46:08 +00:00
pksingh41
4b0a6d27f9 Merge pull request #1833 from Alfresco/ACS-4636-CreateTagCountParamSupport
[ACS-4636] create tag count param support
2023-03-29 13:26:45 +05:30
Praveen Singh
b432fdc6a3 Addressed review comments 2023-03-29 11:17:00 +05:30
alfresco-build
7d62c89708 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-28 11:09:25 +00:00
alfresco-build
e79fcf64a5 [maven-release-plugin][skip ci] prepare release 20.121 2023-03-28 11:09:22 +00:00
kcichonczyk
5df4cfff58 [ACS-4929][ACS-4927] transform-service and transform-core version bump (#1837) 2023-03-28 11:42:33 +02:00
alfresco-build
66ab0c4f46 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-28 07:41:54 +00:00
alfresco-build
1d1252438c [maven-release-plugin][skip ci] prepare release 20.120 2023-03-28 07:41:50 +00:00
MohinishSah
e4ac036f9f Merge pull request #1609 from Alfresco/feature/ACA-4619-Self-service-User-password-reset-ADW
Feature/aca 4619 self service user password reset adw
2023-03-28 06:56:49 +00:00
suneet.gupta
a9ec842358 Merge branch 'master' of github.com:Alfresco/alfresco-community-repo into ACS-4636-CreateTagCountParamSupport 2023-03-28 12:18:42 +05:30
alfresco-build
9590051941 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-27 17:12:19 +00:00
alfresco-build
37618bd56a [maven-release-plugin][skip ci] prepare release 20.119 2023-03-27 17:12:14 +00:00
Tom Page
8bb30643d4 Merge pull request #1790 from Alfresco/feature/ACS-4779-Count_isssue_for_GET_call
ACS-4779:Count field issue for GET call
2023-03-27 17:23:27 +01:00
Tom Page
f0e0819bc5 ACS-4779 Remove failing integration test.
There is no way that the changes to TagsImpl should have affected shared links and so this
test must be failing due to interactions with other tests (e.g. a change in ordering, or
unexpected data in the system).

Notably a comment above the test suggests it may be duplicated by testSharedLinkCreateGetDelete
(which is another unweildy test that covers a large number of difference scenarios). The two
tests definitely contain a large amount of duplicated code.
2023-03-27 16:32:13 +01:00
suneet.gupta
5999a448d4 Merge branch 'master' of github.com:Alfresco/alfresco-community-repo into ACS-4636-CreateTagCountParamSupport 2023-03-27 13:57:30 +05:30
Mohinish Sah
8f00b44a03 Merge remote-tracking branch 'origin/master' into feature/ACA-4619-Self-service-User-password-reset-ADW 2023-03-27 13:07:01 +05:30
alfresco-build
c0d1b33201 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-26 00:06:25 +00:00
alfresco-build
4053daaf1a [maven-release-plugin][skip ci] prepare release 20.118 2023-03-26 00:06:23 +00:00
Alfresco CI User
6942294780 [force] Force release for 2023-03-26. 2023-03-26 00:03:13 +00:00
Tom Page
384177a9d9 Merge pull request #1826 from Alfresco/feature/ACS-4863_ValidateNodeWithoutPath
ACS-4863 Add method validateOrLookupNode without path.
2023-03-24 13:53:44 +00:00
alfresco-build
bbdeb5ae97 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-24 12:17:17 +00:00
alfresco-build
95fb286c14 [maven-release-plugin][skip ci] prepare release 20.117 2023-03-24 12:17:14 +00:00
Tom Page
0652cea296 ACS-4863 Move new validation method to interface as a default implementation. 2023-03-24 11:44:55 +00:00
Tom Page
a86a954771 Merge pull request #1829 from Alfresco/feature/ACS-4863_InvestigateTestFailure
ACS-4863 Restore code to allow aliases in tag and category APIs.
2023-03-24 11:37:15 +00:00
Tom Page
c27a44d711 ACS-4863 Remove test for invalid URL.
This test behaves differently against community and enterprise as the double slash is treated differently.
2023-03-24 10:16:28 +00:00
Krystian Dabrowski
ef089472fb ACS-4915: Editing an orphaned tag results in the tag being deleted (#1823)
* ACS-4915: Editing an orphaned tag results in the tag being deleted
2023-03-24 10:55:12 +01:00
alfresco-build
5769cbe54e [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-24 09:03:52 +00:00
alfresco-build
9899f16d61 [maven-release-plugin][skip ci] prepare release 20.116 2023-03-24 09:03:48 +00:00
Tom Page
219acd6c53 Revert "Revert "ACS-4863 Allow referencing nodes by aliases for tag and category application. (#1822)""
This reverts commit 70b7d5a1f8.
2023-03-24 08:21:11 +00:00
Tom Page
70b7d5a1f8 Revert "ACS-4863 Allow referencing nodes by aliases for tag and category application. (#1822)"
This reverts commit dafa77d0a0.
2023-03-24 08:20:50 +00:00
alfresco-build
279679d78a [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-24 07:03:42 +00:00
alfresco-build
6d1dcf6c7e [maven-release-plugin][skip ci] prepare release 20.115 2023-03-24 07:03:39 +00:00
suneet.gupta
18810de7d0 Merge branch 'master' of github.com:Alfresco/alfresco-community-repo into ACS-4636-CreateTagCountParamSupport 2023-03-24 08:15:46 +05:30
Piotr Żurek
fb119565dc ACS-4888 Use Keycloak free tas-utility (#1827) 2023-03-23 18:29:19 +01:00
Tom Page
10b0d7b5f0 ACS-4863 Ensure we don't accidentally introduce circular reference. 2023-03-23 16:01:07 +00:00
Tom Page
36292d749e ACS-4779 Simplify list creation in test. 2023-03-23 13:58:45 +00:00
Tom Page
c1d424b386 Merge master into ACS-4779-Count_isssue_for_GET_call. 2023-03-23 13:56:54 +00:00
Tom Page
06c6efc6c9 ACS-4779 Remove duplicate @BeforeClass method. 2023-03-23 13:51:47 +00:00
suneet.gupta
626e5b34ef [ACS-4636] Added count support for creation of tags to a node 2023-03-23 18:35:12 +05:30
Tom Page
a549859cbe ACS-4863 Add method validateOrLookupNode without path. 2023-03-23 09:11:48 +00:00
alfresco-build
f2d858f911 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-22 17:39:49 +00:00
alfresco-build
808a7c67b7 [maven-release-plugin][skip ci] prepare release 20.114 2023-03-22 17:39:45 +00:00
Tom Page
dafa77d0a0 ACS-4863 Allow referencing nodes by aliases for tag and category application. (#1822) 2023-03-22 16:54:01 +00:00
Tom Page
fd96c90c08 ACS-4779 Remove test for unsupported use case. 2023-03-22 16:02:55 +00:00
Tom Page
a41fcdff0f ACS-4779 Ensure we only include the count for tags in the GET response when requested. 2023-03-22 15:18:37 +00:00
Tom Page
ab461e34af ACS-4779 Tidy test class. 2023-03-22 14:48:01 +00:00
Tom Page
c92ef4393c Merge master into feature branch. 2023-03-22 14:46:15 +00:00
alfresco-build
ebdc9e159e [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-22 13:30:35 +00:00
alfresco-build
d885c47df7 [maven-release-plugin][skip ci] prepare release 20.113 2023-03-22 13:30:31 +00:00
Piotr Żurek
a1ccc14a93 ACS- 4752 keycloak migration - resource server role (#1818) 2023-03-22 12:58:13 +01:00
alfresco-build
0023612623 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-22 10:54:12 +00:00
alfresco-build
abf9bf8d71 [maven-release-plugin][skip ci] prepare release 20.112 2023-03-22 10:54:08 +00:00
Maciej Pichura
162e164a0c ACS-4755: Bump snakeyaml to 2.0 (#1791)
* ACS-4755: Bump snakeyaml to 2.0

* ACS-4755: Bump jackson to 2.15.0-rc1
2023-03-22 11:02:31 +01:00
alfresco-build
55b0044965 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-22 08:37:22 +00:00
alfresco-build
cfe212d52f [maven-release-plugin][skip ci] prepare release 20.111 2023-03-22 08:37:19 +00:00
MohinishSah
a3cafb7c4c updated surf-webscripts version to 8.38 2023-03-22 13:07:41 +05:30
rrajoria
9ddbda377d Test Case for Client Workspace and changes for Review comments 2023-03-22 12:56:45 +05:30
alfresco-build
e42e2b2c8e [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-21 15:42:06 +00:00
alfresco-build
9090dea75b [maven-release-plugin][skip ci] prepare release 20.110 2023-03-21 15:42:03 +00:00
Krystian Dabrowski
a26ac1f778 ACS-4857: Lookup for root tag in DB and NOT using search engine (#1810)
* ACS-4857: Lookup for root tag in DB and NOT using search engine
Also:
- removing commons-collections exclusion within test scope due to:
"Caused by: java.lang.ClassNotFoundException: org.apache.commons.collections.CollectionUtils"
2023-03-21 15:37:19 +01:00
alfresco-build
8e1d4782b4 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-21 09:49:51 +00:00
alfresco-build
4c409c925b [maven-release-plugin][skip ci] prepare release 20.109 2023-03-21 09:49:48 +00:00
Suneet Gupta
7cbfab81ce [ACS-3916][ACS-3917] Added TagId Validation for Get and Delete methods (#1815)
* [ACS-3916][ACS-3917] Added TagId Validation for Get and Delete methods

* Addressed review comments -
1. Moved duplicate code from ValidateTag methods to a private method
2. Updated the test case
2023-03-21 14:03:27 +05:30
suneet-gupta
addc2c202b [ACS-4886] Changed valdateTag method to validateNode in getTags() method in TagsImpl class 2023-03-21 07:12:21 +00:00
alfresco-build
7b523e5ad9 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-20 16:36:45 +00:00
alfresco-build
7567e83955 [maven-release-plugin][skip ci] prepare release 20.108 2023-03-20 16:36:41 +00:00
Damian Ujma
d6082f84ac ACS-4842 Upgrade Camel and Netty stack (#1814)
* ACS-4842 Update camel to 3.20.2

* ACS-4842 Update gytheio to 0.18
2023-03-20 16:07:19 +01:00
alfresco-build
4f58031178 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-19 00:08:08 +00:00
alfresco-build
7aff9366ce [maven-release-plugin][skip ci] prepare release 20.107 2023-03-19 00:08:05 +00:00
Alfresco CI User
58235fd891 [force] Force release for 2023-03-19. 2023-03-19 00:03:20 +00:00
alfresco-build
bb204c4cea [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-16 18:42:27 +00:00
alfresco-build
ae29ae8581 [maven-release-plugin][skip ci] prepare release 20.106 2023-03-16 18:42:24 +00:00
Jared Ottley
4b351fbfdc [MNT-23553] REST API call fails when using Oracle database
- Remove semicolon from sql
2023-03-16 11:56:00 -06:00
alfresco-build
3e9964d53f [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-16 08:22:17 +00:00
alfresco-build
23761f6c56 [maven-release-plugin][skip ci] prepare release 20.105 2023-03-16 08:22:13 +00:00
Piotr Żurek
2f8c283ada ACS-4844 Use matching json-smart version (#1805) 2023-03-16 07:58:25 +01:00
alfresco-build
5232b8c3fe [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-15 16:35:10 +00:00
alfresco-build
b90938bb99 [maven-release-plugin][skip ci] prepare release 20.104 2023-03-15 16:35:07 +00:00
Piotr Żurek
d243ac04c6 ACS-4844 json-path should be provided by the repo to avoid conflicts with AMPs (#1803) 2023-03-15 16:49:17 +01:00
alfresco-build
e651f6e104 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-15 14:55:19 +00:00
alfresco-build
e4776e2594 [maven-release-plugin][skip ci] prepare release 20.103 2023-03-15 14:55:15 +00:00
Tom Page
acc5425d68 ACS-4759 Replace default password hashing algorithm. (#1789)
ACS-4759 Replace default password hashing algorithm with bcrypt10.

Update tests to use sha256 hashing and fix tests that relied on md4 being the default hashing algorithm.

Remove test for default password hashing algorithm since this is being overridden for the tests anyway.
2023-03-15 14:11:25 +00:00
alfresco-build
a96e805d52 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-15 09:37:38 +00:00
alfresco-build
45a9a1ae49 [maven-release-plugin][skip ci] prepare release 20.102 2023-03-15 09:37:34 +00:00
Piotr Żurek
bf18c6b419 ACS-4751 Keycloak Migration - OAuth2 Client Role (#1798) 2023-03-15 09:53:17 +01:00
dependabot[bot]
e728489b69 Bump groovy-json from 3.0.12 to 3.0.16 (#1800)
Bumps [groovy-json](https://github.com/apache/groovy) from 3.0.12 to 3.0.16.
- [Release notes](https://github.com/apache/groovy/releases)
- [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>
2023-03-15 09:52:13 +01:00
Krystian Dabrowski
f2fdf958f2 ACS-4023: Update GET /tags to support getting tags by name (#1766)
* ACS-4023: Update GET /tags to support getting tags by name
2023-03-15 09:46:58 +01:00
alfresco-build
0cb03c2a38 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-14 09:23:52 +00:00
alfresco-build
b13ca1f68b [maven-release-plugin][skip ci] prepare release 20.101 2023-03-14 09:23:49 +00:00
dependabot[bot]
484699b266 Bump groovy from 3.0.12 to 3.0.16 (#1801)
Bumps [groovy](https://github.com/apache/groovy) from 3.0.12 to 3.0.16.
- [Release notes](https://github.com/apache/groovy/releases)
- [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>
2023-03-14 09:55:22 +01:00
alfresco-build
a15161c872 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-13 21:34:16 +00:00
alfresco-build
b3a6150655 [maven-release-plugin][skip ci] prepare release 20.100 2023-03-13 21:34:13 +00:00
Damian Ujma
42e06da4f8 ACS-4137 Change the 'build-multiarch-docker-image' profile phase to package (#1799)
* ACS-4137 Change the build-multiarch-docker-image profile phase to package

* ACS-4137 Change the build-multiarch-docker-image profile phase to package
2023-03-13 22:05:22 +01:00
alfresco-build
4ac30c2173 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-13 15:30:38 +00:00
alfresco-build
d1d84d849e [maven-release-plugin][skip ci] prepare release 20.99 2023-03-13 15:30:35 +00:00
dependabot[bot]
40af1799fe Bump alfresco/alfresco-base-tomcat from tomcat9-jre17-rockylinux8-202209261711 to tomcat9-jre17-rockylinux8-202303081618 in /packaging/docker-alfresco (#1792)
* Bump alfresco/alfresco-base-tomcat in /packaging/docker-alfresco

Bumps alfresco/alfresco-base-tomcat from tomcat9-jre17-rockylinux8-202209261711 to tomcat9-jre17-rockylinux8-202303081618.

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

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

* ACS-4768 Update freetype package for Rocky Linux 8.7

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Damian.Ujma@hyland.com <Damian.Ujma@hyland.com>
2023-03-13 16:03:51 +01:00
alfresco-build
f59e4a044a [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-13 10:24:01 +00:00
alfresco-build
5924263c18 [maven-release-plugin][skip ci] prepare release 20.98 2023-03-13 10:23:58 +00:00
Damian Ujma
082e38692f ACS-4137 Produce Multi-Arch Docker images (#1797)
* Revert "Revert "ACS-4137 Produce Multi-Arch Docker images (#1656)" (#1796)"

This reverts commit ddbaabb713.

* ACS-4137 Remove default multi-arch docker-maven-plugin configuration
2023-03-13 10:44:06 +01:00
alfresco-build
f5c4112e65 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-12 00:06:40 +00:00
alfresco-build
ad8251c054 [maven-release-plugin][skip ci] prepare release 20.97 2023-03-12 00:06:37 +00:00
Alfresco CI User
32d0182096 [force] Force release for 2023-03-12. 2023-03-12 00:03:26 +00:00
alfresco-build
2ac9779a3b [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-10 10:45:43 +00:00
alfresco-build
af999fb0fd [maven-release-plugin][skip ci] prepare release 20.96 2023-03-10 10:45:40 +00:00
Damian Ujma
ddbaabb713 Revert "ACS-4137 Produce Multi-Arch Docker images (#1656)" (#1796)
This reverts commit 212fa9b362.
2023-03-10 11:20:43 +01:00
alfresco-build
b93136f2c0 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-10 09:06:46 +00:00
alfresco-build
923aadb12a [maven-release-plugin][skip ci] prepare release 20.95 2023-03-10 09:06:42 +00:00
Wojtek Świętoń
212fa9b362 ACS-4137 Produce Multi-Arch Docker images (#1656)
* ACS-4137 Update pom.xml to use buildx

* ACS-4137 Update travis.yml to use buildx

* ACS-4137 Update travis.yml to use buildx, newest docker version

* ACS-4137 reverted unnecessary changes in travis.yml file

* ACS-4137 Change deprecated <dockerFileDir> property to <contextDir>. Moved <build> section from subpoms to global pom.

* ACS-4137 POM indentation fixes

* ACS-4137 Fix building a multiarch image (#1697)

* ACS-4137 Test wih GHA [ags][tas]

* ACS-4137 Test wih GHA [ags][tas]

* ACS-4137 Fix setting network [ags][tas]

* ACS-4137 Fix creating builder [ags][tas]

* ACS-4137 Change image tag [ags][tas]

* ACS-4137 Fix starting the registry [ags][tas]

* ACS-4137 Refactor code [ags][tas]

* ACS-4137 Uncomment all jobs [tas][ags]

* ACS-4137 Improve prepare_buildx.sh [tas][ags]

* ACS-4137 Implement timeout + remove hardcoded base image tag [tas][ags]

* ACS-4137 Added exec-maven-plugin to build-push-image for alfresco-governance-repository-community-base image

* ACS-4137 Generalize prepare_buildx.sh + increase registry timeout

* ACS-4137 merged local.registry.host and local.registry.port. Builder name changed to entitled-builder. In prepare_builder script added localhost registry checking

* ACS-4137 added build-multiarch-docker-images maven profile

* ACS-4137 added <BASE_IMAGE> arg to build-docker-images profile

* ACS-4137 added combine.self="override" attribute to configuration in build-docker-images profile to not use buildx. Delete redundant base.image.tag

* ACS-4137 Push docker images to local repository

* ACS-4137 Remove useless scripts

* ACS-4137 Move builder.name and local.registry properties to main pom.xml

* ACS-4137 Remove useless properties definitions

---------

Co-authored-by: Damian.Ujma@hyland.com <Damian.Ujma@hyland.com>
Co-authored-by: Damian Ujma <92095156+damianujma@users.noreply.github.com>
2023-03-10 09:20:22 +01:00
adam.zakrzewski
267bd98d21 ACS-4779: Adding update for tests after Tome's review 2023-03-08 16:14:21 +01:00
adam.zakrzewski
bcaeedb162 ACS-4779:Count field exists in response for get list of tags even when that field is not included. Other issue is that count field is not present when we do GET call with included count for /tags/{tagId} 2023-03-08 14:39:47 +01:00
adam.zakrzewski
f93bced905 ACS-4779:Count field exists in response for get list of tags even when that field is not included. Other issue is that count field is not present when we do GET call with included count for /tags/{tagId} 2023-03-08 14:27:16 +01:00
alfresco-build
c3e37b96b4 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-08 10:53:06 +00:00
alfresco-build
517f40e150 [maven-release-plugin][skip ci] prepare release 20.94 2023-03-08 10:53:02 +00:00
dependabot[bot]
f86d0f1fd2 Bump alfresco-jlan-embed from 7.2 to 7.4 (#1773)
Bumps alfresco-jlan-embed from 7.2 to 7.4.

---
updated-dependencies:
- dependency-name: org.alfresco:alfresco-jlan-embed
  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>
2023-03-08 10:38:40 +01:00
alfresco-build
09da8640a0 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-08 09:14:04 +00:00
alfresco-build
6bd9bf768e [maven-release-plugin][skip ci] prepare release 20.93 2023-03-08 09:14:00 +00:00
pzurek
f75c0c8f9e Just to check if the recent problems are related to Dependabot commits 2023-03-08 09:14:54 +01:00
dependabot[bot]
ff9364a3b1 Bump utility from 3.0.58 to 3.0.61 (#1776) 2023-03-07 19:22:57 +00:00
dependabot[bot]
db832663b4 Bump dependency.activemq.version from 5.17.1 to 5.17.4 (#1778) 2023-03-07 11:39:30 +00:00
alfresco-build
890e1173c5 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-07 11:36:43 +00:00
alfresco-build
9399c38741 [maven-release-plugin][skip ci] prepare release 20.92 2023-03-07 11:36:39 +00:00
mikolajbrzezinski
bf16e843fd ACS-3975 Fix Intermittent Test Failure (#1785)
Fix Intermittent Test Failure
2023-03-07 11:50:33 +01:00
dependabot[bot]
69a5a95dae Bump docker-maven-plugin from 0.40.2 to 0.42.0 (#1784) 2023-03-07 10:50:09 +00:00
alfresco-build
be37440e24 [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-07 10:29:48 +00:00
alfresco-build
6504406861 [maven-release-plugin][skip ci] prepare release 20.91 2023-03-07 10:29:44 +00:00
dependabot[bot]
38d7dbfa00 Bump json from 20220320 to 20230227 (#1779)
Bumps [json](https://github.com/douglascrockford/JSON-java) from 20220320 to 20230227.
- [Release notes](https://github.com/douglascrockford/JSON-java/releases)
- [Changelog](https://github.com/stleary/JSON-java/blob/master/docs/RELEASES.md)
- [Commits](https://github.com/douglascrockford/JSON-java/commits)

---
updated-dependencies:
- dependency-name: org.json:json
  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>
2023-03-07 10:46:42 +01:00
dependabot[bot]
1ed635275f Bump commons-fileupload from 1.4 to 1.5 (#1749)
Bumps commons-fileupload from 1.4 to 1.5.

---
updated-dependencies:
- dependency-name: commons-fileupload:commons-fileupload
  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>
2023-03-07 10:46:26 +01:00
Domenico Sibilio
7b87ee628d ACS-4776 Finalize deprecation of BitlyUrlShortenerImpl (#1787) 2023-03-07 10:32:14 +01:00
alfresco-build
9cff80362d [maven-release-plugin][skip ci] prepare for next development iteration 2023-03-05 00:06:40 +00:00
alfresco-build
8311c889bb [maven-release-plugin][skip ci] prepare release 20.90 2023-03-05 00:06:38 +00:00
Alfresco CI User
bd5b5a240e [force] Force release for 2023-03-05. 2023-03-05 00:03:38 +00:00
Mohinish Sah
91f3edf8e9 incorporated review comments 2023-03-02 22:10:54 +05:30
Mohinish Sah
479724365e incorporated review comments 2023-03-02 22:04:50 +05:30
Mohinish Sah
bb1d5899d9 Merge remote-tracking branch 'origin/master' into feature/ACA-4619-Self-service-User-password-reset-ADW 2023-03-02 21:46:53 +05:30
Mohinish Sah
7ab5e8afd0 Updated the client App name 2023-03-01 18:45:08 +05:30
Mohinish Sah
5107fdfe41 resolved review comments 2023-03-01 12:45:15 +05:30
alfresco-build
c2d13e3177 [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-27 11:08:57 +00:00
alfresco-build
e8f50da5a2 [maven-release-plugin][skip ci] prepare release 20.89 2023-02-27 11:08:54 +00:00
Tom Page
2053e3b83a Code freeze testing. 2023-02-27 09:35:11 +00:00
alfresco-build
bcc2eadba6 [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-26 00:06:28 +00:00
alfresco-build
eb40dd3a45 [maven-release-plugin][skip ci] prepare release 20.88 2023-02-26 00:06:25 +00:00
Alfresco CI User
4c511423d5 [force] Force release for 2023-02-26. 2023-02-26 00:03:24 +00:00
alfresco-build
b12b21e773 [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-24 07:28:12 +00:00
alfresco-build
569078f408 [maven-release-plugin][skip ci] prepare release 20.87 2023-02-24 07:28:08 +00:00
Damian Ujma
90de678d7d ACS-3750 Fix cancelled workflow condition (#1768) 2023-02-23 16:11:09 +01:00
alfresco-build
0a75cbbc67 [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-22 11:38:44 +00:00
alfresco-build
c5f174a55d [maven-release-plugin][skip ci] prepare release 20.86 2023-02-22 11:38:42 +00:00
Piotr Żurek
119596647a ACS-4424 AGS Community tests for ES (#1761) 2023-02-22 12:08:30 +01:00
Piyush Joshi
e5d5969fc4 [ACS-3960][ACS-4339] Count is only returned for a tag if it is greater than zero (#1755)
* Added fix for ACS-3960

* Added fix for ACS-3960

* Added fix for ACS-3960

* Added formatting

* Added Fix for ACS-3960

* Revert "Added Fix for ACS-3960"

This reverts commit c06dba2d93.

* Addressed review comment

Co-authored-by: Tom Page <tpage-alfresco@users.noreply.github.com>

* Issue Fixed and added unit test cases.

* Removed extra assertion in testcases.

---------

Co-authored-by: suneet.gupta <suneet.gupta@hyland.com>
Co-authored-by: Tom Page <tpage-alfresco@users.noreply.github.com>
2023-02-22 10:21:59 +05:30
alfresco-build
b79dc538c9 [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-19 00:17:09 +00:00
alfresco-build
72965efb57 [maven-release-plugin][skip ci] prepare release 20.85 2023-02-19 00:17:06 +00:00
Alfresco CI User
d467c3cdb1 [force] Force release for 2023-02-19. 2023-02-19 00:03:32 +00:00
alfresco-build
73d919435c [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-15 17:42:28 +00:00
alfresco-build
5fb86e1bbc [maven-release-plugin][skip ci] prepare release 20.84 2023-02-15 17:42:23 +00:00
Krystian Dabrowski
23de0fefd7 ACS-4633: Duplicated tag is not detected when tag string contains upper case (#1750) 2023-02-15 18:13:19 +01:00
Piyush Joshi
7c3e8a2549 [MNT-22633] Creation, Modification TimeStamp values setted for download as zip (#1717)
* Creation, Modification date timestamp added to zip file

* Addressed review comments

* Addressed review comments

* Revert "Addressed review comments"

This reverts commit 58214ee427.

* Addressed review comments

* Revert "Addressed review comments"

This reverts commit a584f53023.

* Update ZipDownloadExporter.java

Addresed review comments

---------

Co-authored-by: suneet.gupta <suneet.gupta@hyland.com>
2023-02-15 21:45:46 +05:30
alfresco-build
6a3dbff290 [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-13 12:39:27 +00:00
alfresco-build
0ca29a76a9 [maven-release-plugin][skip ci] prepare release 20.83 2023-02-13 12:39:23 +00:00
George Evangelopoulos
561e7330e3 ACS-4027: add E2Es for DELETE /tags/{tagsId} endpoint (#1743)
* ACS-4027: add E2Es and helper methods
2023-02-13 13:31:53 +02:00
alfresco-build
628b267a2b [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-12 00:06:42 +00:00
alfresco-build
ea9687ac33 [maven-release-plugin][skip ci] prepare release 20.82 2023-02-12 00:06:39 +00:00
Alfresco CI User
4292a3ce1c [force] Force release for 2023-02-12. 2023-02-12 00:03:14 +00:00
alfresco-build
09721dca4e [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-11 17:33:49 +00:00
alfresco-build
0e4020452c [maven-release-plugin][skip ci] prepare release 20.81 2023-02-11 17:33:46 +00:00
Krystian Dabrowski
96c1464b6c ACS-4026: Create orphaned tag with POST /tags (#1748)
* ACS-4026: Create orphaned tag with POST /tags
2023-02-10 16:51:22 +01:00
alfresco-build
9457e019ef [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-10 13:03:16 +00:00
alfresco-build
41d82cc5ce [maven-release-plugin][skip ci] prepare release 20.80 2023-02-10 13:03:13 +00:00
Suneet Gupta
439e8587cf Changed line separation formatting to unix (#1741) 2023-02-08 17:47:06 +05:30
George Evangelopoulos
a59234f47f ACS-4027: Introduce changes to support removing tag from all associated nodes (#1709)
* ACS-4027: Introduce changes to support removing tag from all associated nodes

* ACS-4027: fix implementation and add tests
2023-02-07 18:32:52 +02:00
Domenico Sibilio
c9522f299e ACS-3750 Use set Git token instead of cached one (#1736) 2023-02-07 16:20:18 +01:00
alfresco-build
30dd78a6ab [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-07 11:42:09 +00:00
alfresco-build
008134f5b0 [maven-release-plugin][skip ci] prepare release 20.79 2023-02-07 11:42:05 +00:00
Krystian Dabrowski
285ebc29a4 ACS-4154: Add category count to relevant CRUD endpoints for categories (#1724)
* ACS-4154: Add category count to relevant CRUD endpoints for categories
2023-02-07 11:14:35 +01:00
alfresco-build
9c6e8aad9c [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-05 00:06:49 +00:00
alfresco-build
915fe193e2 [maven-release-plugin][skip ci] prepare release 20.78 2023-02-05 00:06:46 +00:00
Alfresco CI User
a2756aa868 [force] Force release for 2023-02-05. 2023-02-05 00:03:19 +00:00
Domenico Sibilio
b28e02c6fa ACS-3750 Improve branch detection in if conditions (#1722) 2023-02-02 17:16:06 +01:00
alfresco-build
8d00a1ab61 [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-02 12:45:11 +00:00
alfresco-build
a86ad3c973 [maven-release-plugin][skip ci] prepare release 20.77 2023-02-02 12:45:08 +00:00
Piotr Żurek
2cdbe6f306 ACS-4180 Add localized properties to the repo event (#1714) 2023-02-02 12:22:08 +01:00
Tom Page
556e1923d1 Merge pull request #1720 from Alfresco/feature/ACS-4155_FixWebscriptsForES
ACS-4155 Update webscripts since we only index full category path in ES.
2023-02-01 13:10:58 +00:00
Tom Page
22e8a506ff ACS-4155 We only index full category path in ES. 2023-02-01 12:19:50 +00:00
alfresco-build
f63c9ee8c4 [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-01 12:16:19 +00:00
alfresco-build
b5b9b9e2c4 [maven-release-plugin][skip ci] prepare release 20.76 2023-02-01 12:16:15 +00:00
pzurek
9e88a6562e Trigger CI 2023-02-01 10:44:42 +01:00
alfresco-build
dbddc08fcc [maven-release-plugin][skip ci] prepare for next development iteration 2023-02-01 09:08:32 +00:00
alfresco-build
9b5e69e070 [maven-release-plugin][skip ci] prepare release 20.75 2023-02-01 09:08:28 +00:00
pzurek
23f6f6fc90 [force] release for downstream projects 2023-02-01 10:04:39 +01:00
dependabot[bot]
9d8e93474c Bump postgresql from 42.5.0 to 42.5.2 (#1718) 2023-02-01 08:19:27 +00:00
alfresco-build
3d450e1d8d [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-31 14:28:10 +00:00
alfresco-build
e587ef124e [maven-release-plugin][skip ci] prepare release 20.74 2023-01-31 14:28:06 +00:00
Domenico Sibilio
34c8f9e431 ACS-4455 Bump alfresco-build-tools to v1.33.0 (#1713) 2023-01-31 14:57:10 +01:00
alfresco-build
736cc74479 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-31 06:57:34 +00:00
alfresco-build
419f498c5a [maven-release-plugin][skip ci] prepare release 20.73 2023-01-31 06:57:32 +00:00
pzurek
f91a35b992 [force] release for downstream projects 2023-01-31 07:54:24 +01:00
dependabot[bot]
1c5a9a74c7 Bump assertj-core from 3.23.1 to 3.24.2 (#1689) 2023-01-30 14:02:25 +00:00
dependabot[bot]
2652552da7 Bump acs-event-model from 0.0.16 to 0.0.18 (#1710) 2023-01-30 13:58:36 +00:00
alfresco-build
ff39addcce [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-29 00:06:07 +00:00
alfresco-build
74a8c216d0 [maven-release-plugin][skip ci] prepare release 20.72 2023-01-29 00:06:04 +00:00
Alfresco CI User
e1a36ae5db [force] Force release for 2023-01-29. 2023-01-29 00:03:03 +00:00
alfresco-build
f1f576b1c7 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-27 08:32:16 +00:00
alfresco-build
9a506410c3 [maven-release-plugin][skip ci] prepare release 20.71 2023-01-27 08:32:13 +00:00
kcichonczyk
b401bbfe2a [ACS-4418] Align IE/SS versions (#1705) 2023-01-26 13:31:03 +01:00
alfresco-build
b302422c52 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-25 18:03:35 +00:00
alfresco-build
3b57d16790 [maven-release-plugin][skip ci] prepare release 20.70 2023-01-25 18:03:33 +00:00
tiagosalvado10
781f045503 [MNT-23414] Bulk import - convert empty values to null for certain types (#1688) 2023-01-25 17:28:40 +00:00
alfresco-build
80e1777f92 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-25 17:06:32 +00:00
alfresco-build
671b612ce4 [maven-release-plugin][skip ci] prepare release 20.69 2023-01-25 17:06:30 +00:00
evasques
9637d514dd MNT-23411 Option to disable events2 (#1703)
* Added configuration to disable events2 so the behaviours are not bootstrapped. Additionally added options to enable/disable on runtime
* Added unit test
2023-01-25 16:15:17 +00:00
alfresco-build
5cba07d8de [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-25 15:50:23 +00:00
alfresco-build
ce4edb1b90 [maven-release-plugin][skip ci] prepare release 20.68 2023-01-25 15:50:20 +00:00
Domenico Sibilio
8951bfa4da ACS-3750 Bump alfresco-build-tools to v1.32.0 (#1702) 2023-01-25 12:22:00 +01:00
Krystian Dabrowski
37ec795358 ACS-4362: Fix returned HTTP error status for invalid note type (#1691)
* ACS-4362: Create categories and tags - fix returned HTTP error status for invalid note type
2023-01-24 17:42:12 +01:00
alfresco-build
ee7a5370f8 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-24 13:18:31 +00:00
alfresco-build
b37b683683 [maven-release-plugin][skip ci] prepare release 20.67 2023-01-24 13:18:28 +00:00
George Evangelopoulos
281009bc50 ACS-4035: support for removing a piece of content from a category (#1670)
* ACS-4035: support for removing a piece of content from a category
2023-01-24 14:29:05 +02:00
Tom Page
8a1b81ab61 Merge pull request #1698 from Alfresco/feature/ACS-4144_GetCategories
ACS-4144 Add support for getting categories in ES by allowing access to the prefix helper method.
2023-01-24 12:26:29 +00:00
alfresco-build
da583c24be [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-24 12:19:52 +00:00
alfresco-build
e3b43f12d2 [maven-release-plugin][skip ci] prepare release 20.66 2023-01-24 12:19:49 +00:00
Tom Page
d233850ab8 Merge pull request #1700 from Alfresco/feature/ACS-4464_PrepareAndBuild
ACS-4464 Always build application when build or prepare are called.
2023-01-24 11:51:25 +00:00
Tom Page
d7edaa5eaf ACS-4464 Always build application when build or prepare are called.
If build is called then we definitely should be building the application. When prepare is called then we want to
prevent further builds running if the application doesn't compile.
2023-01-24 10:57:37 +00:00
alfresco-build
965aa66a7e [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-24 08:14:11 +00:00
alfresco-build
b4bfd65031 [maven-release-plugin][skip ci] prepare release 20.65 2023-01-24 08:14:08 +00:00
Piotr Żurek
6841388b4f Upgrade Spring framework and CXF (#1695) 2023-01-24 08:26:16 +01:00
Tom Page
edb2a01d8f ACS-4144 Add support for getting categories in ES by allowing access to the prefix helper method. 2023-01-23 14:38:59 +00:00
alfresco-build
f87eaf8659 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-22 00:07:37 +00:00
alfresco-build
e9773fb5d6 [maven-release-plugin][skip ci] prepare release 20.64 2023-01-22 00:07:34 +00:00
Alfresco CI User
148fc6c8f8 [force] Force release for 2023-01-22. 2023-01-22 00:02:52 +00:00
alfresco-build
26d572c96a [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-20 14:47:28 +00:00
alfresco-build
5fc5b52e7e [maven-release-plugin][skip ci] prepare release 20.63 2023-01-20 14:47:25 +00:00
MohinishSah
1d2e4b7a07 updated AOS and GoogleDrive Milestone version 2023-01-20 19:50:29 +05:30
alfresco-build
ef496422e5 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-20 10:29:35 +00:00
alfresco-build
d3c7ecc47e [maven-release-plugin][skip ci] prepare release 20.62 2023-01-20 10:29:32 +00:00
Domenico Sibilio
3461a67120 ACS-4177 Improve rendition API tests retry logic (#1692) 2023-01-20 10:52:04 +01:00
alfresco-build
004d9cfcf8 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-16 11:18:21 +00:00
alfresco-build
33c52532cc [maven-release-plugin][skip ci] prepare release 20.61 2023-01-16 11:18:18 +00:00
rrajoria
20d3740ef8 Updating aos version to 1.6.0-A3 2023-01-16 16:24:31 +05:30
krdabrowski
c228bfac1f Acs 4400 multiple same categories can be linked from content or folder (#1675)
ACS-4400: Multiple same categories can be linked from content or folder
2023-01-16 11:40:37 +01:00
alfresco-build
2b363fb315 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-15 13:56:12 +00:00
alfresco-build
b310bfbb8d [maven-release-plugin][skip ci] prepare release 20.60 2023-01-15 13:56:08 +00:00
tiagosalvado10
95ab83d2b1 [MNT-23396] [MNT-23391] Change call stack depth limit to be only applied to custom scripts / Clean scope only for custom scripts (#1592)
* [MNT-23158] Change call stack depth limit to be only applied to custom scripts (as memory and time limits)

* [MNT-23158] Changed how memory usage is obtained

* [MNT-23391] Only clean scope if script is not considered secure (custom script)
2023-01-15 13:07:12 +00:00
alfresco-build
bfc07308fd [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-15 00:06:20 +00:00
alfresco-build
543f24bbfc [maven-release-plugin][skip ci] prepare release 20.59 2023-01-15 00:06:18 +00:00
Alfresco CI User
bac6db19fe [force] Force release for 2023-01-15. 2023-01-15 00:03:12 +00:00
krdabrowski
0197b0e221 ACS-4033: List linked categories for a particular node (#1672)
* ACS-4033: List linked categories for a particular node - GET /nodes/{nodeId}/category-links
2023-01-13 18:10:46 +01:00
Maciej Pichura
d3d1aaeba1 ACS-4160: Fixing and making GetTopCategories more re-usable (#1674)
* ACS-4160: Fixing and making GetTopCategories more re-usable

* Fixing a TYPO
2023-01-13 17:07:45 +01:00
alfresco-build
96384a289b [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-12 12:40:59 +00:00
alfresco-build
4f98727c7f [maven-release-plugin][skip ci] prepare release 20.58 2023-01-12 12:40:56 +00:00
Damian Ujma
b773307a0b ACS-3841 Use AlphabeticalPriorityInterceptor from alfresco-tas-utility (#1671) 2023-01-12 12:51:52 +01:00
alfresco-build
9239817226 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-10 15:50:30 +00:00
alfresco-build
b144a62836 [maven-release-plugin][skip ci] prepare release 20.57 2023-01-10 15:50:27 +00:00
Damian Ujma
868d783746 ACS-3841 Migrate to GHA (#1631)
* ACS-3841 Use configure-git-author, rename steps, remove always from maven cache clean step

* ACS-3841 Fix PostgreSQL 13.7 tests step name

* ACS-3841 Fix update_downstream job

* ACS-3841 Set global option for configure-git-author action

* ACS-3841 Update license header

* ACS-3841 Update configure-git-author version + improve uploading artifacts

* ACS-3841 Improve uploading artifacts

* ACS-3841 Fix uploading artifacts

* ACS-3841 Rename jobs names + revert removed functions

* ACS-3841 Fix step condition

* ACS-3841 Update to latest alfresco-build-tools

Co-authored-by: mikolajbrzezinski <mikolaj.brzezinski@hyland.com>
2023-01-10 15:50:11 +01:00
Travis CI User
9059ec04b2 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-09 19:25:11 +00:00
Travis CI User
3b09af417c [maven-release-plugin][skip ci] prepare release 20.56 2023-01-09 19:25:08 +00:00
tiagosalvado10
4749166080 [MNT-23379] Added sleep between document creation and update to prevent test failures (#1668) 2023-01-09 18:40:36 +00:00
krdabrowski
e4e4ed214a ACS-4034: Assign a piece of content to a category (#1655)
* ACS-4034: Assign a piece of content to a category - POST /nodes/{nodeId}/category-links
- added also one TAS test for update category covering repeated name case
2023-01-09 16:01:57 +01:00
Travis CI User
6a240b722b [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-08 00:10:57 +00:00
Travis CI User
1792af0254 [maven-release-plugin][skip ci] prepare release 20.55 2023-01-08 00:10:54 +00:00
Alfresco CI User
f8fffc50d0 [force] Force release for 2023-01-08. 2023-01-08 00:03:15 +00:00
Travis CI User
1f301da8f8 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-06 19:04:53 +00:00
Travis CI User
49d032bd76 [maven-release-plugin][skip ci] prepare release 20.54 2023-01-06 19:04:50 +00:00
tiagosalvado10
88a0854548 [MNT-23379] Set site manager permission if node belongs to a site and inheritance flag is disabled (#1657)
* [MNT-23379] Set site manager permission if node belongs to a site and inheritance flag is disabled

* [MNT-23379] Added validation. Added throwable object to error logging.

* [MNT-23379] Added unit test

* [MNT-23379] Changed 'runAs' call to 'runAsSystem' with lambda
2023-01-06 15:43:14 +00:00
Travis CI User
3a032b7366 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-05 14:20:47 +00:00
Travis CI User
fe6a5b355d [maven-release-plugin][skip ci] prepare release 20.53 2023-01-05 14:20:44 +00:00
atkumar14
e4f5aa1f29 [MNT-22965] Updated RM permissions (#1660)
Co-authored-by: suneet-gupta <suneet.gupta@hyland.com>
2023-01-05 19:14:50 +05:30
Travis CI User
010fa108e5 [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-04 22:00:47 +00:00
Travis CI User
4f04e7bf4b [maven-release-plugin][skip ci] prepare release 20.52 2023-01-04 22:00:44 +00:00
Marcin Strankowski
3068ad9969 ACS-2967: While LocalPipelineTransform was reported to cause a warning issue, actually it is already fixed, LocalFailoverTransform however caused same warning (#1658) 2023-01-04 22:25:20 +01:00
Travis CI User
08109eecff [maven-release-plugin][skip ci] prepare for next development iteration 2023-01-04 15:52:26 +00:00
Mohinish Sah
f59ff23a45 Rebase Branch 2022-12-08 16:26:44 +05:30
rrajoria
5e2f1db714 ACA-4619: Forgot Password Changes 2022-12-08 16:21:29 +05:30
rrajoria
67ee2efc60 ACA-4619: Forgot Password Changes 2022-12-08 16:21:29 +05:30
MohinishSah
1e7dc6ed8d update Gdrive version 2022-11-14 10:54:40 +05:30
rrajoria
e5ea6db30c ACA-4619: Forgot Password Changes 2022-11-09 18:11:16 +05:30
rrajoria
78a613b1de ACA-4619: Forgot Password Changes 2022-11-09 18:10:29 +05:30
210 changed files with 12949 additions and 5576 deletions

View File

@@ -53,24 +53,6 @@ updates:
- dependency-name: org.freemarker:freemarker
versions:
- "> 2.3.20-alfresco-patched-20200421"
- dependency-name: org.keycloak:keycloak-adapter-core
versions:
- "> 12.0.2"
- dependency-name: org.keycloak:keycloak-adapter-spi
versions:
- "> 12.0.2"
- dependency-name: org.keycloak:keycloak-authz-client
versions:
- "> 12.0.2"
- dependency-name: org.keycloak:keycloak-common
versions:
- "> 12.0.2"
- dependency-name: org.keycloak:keycloak-core
versions:
- "> 12.0.2"
- dependency-name: org.keycloak:keycloak-servlet-adapter-spi
versions:
- "> 12.0.2"
- dependency-name: org.eclipse.jetty:jetty-server
versions:
- 9.4.38.v20210224

541
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,541 @@
name: Alfresco Community Repo CI
on:
pull_request:
branches:
- feature/**
- fix/**
- master
- release/**
push:
branches:
- feature/**
- fix/**
workflow_call:
workflow_dispatch:
env:
DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USERNAME }}
GITHUB_ACTIONS_DEPLOY_TIMEOUT: 60
LOG_WARN: "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
MAVEN_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
MAVEN_USERNAME: ${{ secrets.NEXUS_USERNAME }}
QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }}
QUAY_USERNAME: ${{ secrets.QUAY_USERNAME }}
TAS_ENVIRONMENT: ./packaging/tests/environment
TAS_SCRIPTS: ../alfresco-community-repo/packaging/tests/scripts
jobs:
prepare:
name: "Prepare"
runs-on: ubuntu-latest
if: >
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- name: "Prepare maven cache and check compilation"
run: bash ./scripts/ci/prepare.sh
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
veracode:
name: "Source Clear Scan (SCA)"
runs-on: ubuntu-latest
needs: [prepare]
if: >
((github.ref_name == 'master' || startsWith(github.ref_name, 'release/')) && github.event_name != 'pull_request') &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- uses: Alfresco/alfresco-build-tools/.github/actions/veracode@v1.33.0
continue-on-error: true
with:
srcclr-api-token: ${{ secrets.SRCCLR_API_TOKEN }}
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
all_unit_tests_suite:
name: "Core, Data-Model, Repository - 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]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- name: "Run tests"
run: |
mvn -B test -pl core,data-model -am -DfailIfNoTests=false
mvn -B test -pl "repository,mmt" -am "-Dtest=AllUnitTestsSuite,AllMmtUnitTestSuite" -DfailIfNoTests=false
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
remote_api_app_context_test_suites:
name: Remote-api - ${{ matrix.testSuite }}
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:
- testSuite: AppContext01TestSuite
compose-profile: default
- testSuite: AppContext02TestSuite
compose-profile: with-transform-core-aio
- testSuite: AppContext03TestSuite
compose-profile: with-transform-core-aio
- testSuite: AppContext04TestSuite
compose-profile: with-transform-core-aio
- testSuite: AppContextExtraTestSuite
compose-profile: default
env:
REQUIRES_INSTALLED_ARTIFACTS: true
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: |
bash ./scripts/ci/init.sh
bash ./scripts/ci/build.sh
- name: "Set transformers tag"
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: "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
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
repository_mariadb_tests:
name: Repository - MariaDB ${{ matrix.version }} tests
runs-on: ubuntu-latest
needs: [prepare]
if: >
(((github.ref_name == 'master' || startsWith(github.ref_name, 'release/')) &&
github.event_name != 'pull_request' &&
!contains(github.event.head_commit.message, '[skip db]')) ||
contains(github.event.head_commit.message, '[db]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
strategy:
fail-fast: false
matrix:
version: ['10.2.18', '10.4', '10.5']
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- name: Run MariaDB ${{ matrix.version }} database
run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mariadb up -d
env:
MARIADB_VERSION: ${{ matrix.version }}
- 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
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
repository_mariadb_10_6_tests:
name: "Repository - MariaDB 10.6 tests"
runs-on: ubuntu-latest
needs: [prepare]
if: >
(((github.ref_name == 'master' || startsWith(github.ref_name, 'release/') || github.event_name == 'pull_request') &&
!contains(github.event.head_commit.message, '[skip db]')) ||
contains(github.event.head_commit.message, '[latest db]') ||
contains(github.event.head_commit.message, '[db]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- name: "Run MariaDB 10.6 database"
run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mariadb up -d
env:
MARIADB_VERSION: 10.6
- 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
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
repository_mysql_tests:
name: Repository - MySQL 8 tests
runs-on: ubuntu-latest
needs: [prepare]
if: >
(((github.ref_name == 'master' || startsWith(github.ref_name, 'release/') || github.event_name == 'pull_request') &&
!contains(github.event.head_commit.message, '[skip db]')) ||
contains(github.event.head_commit.message, '[latest db]') ||
contains(github.event.head_commit.message, '[db]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- name: "Run MySQL 8 database"
run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile mysql up -d
env:
MYSQL_VERSION: 8
- 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
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
repository_postgresql_13_7_tests:
name: "Repository - PostgreSQL 13.7 tests"
runs-on: ubuntu-latest
needs: [prepare]
if: >
(((github.ref_name == 'master' || startsWith(github.ref_name, 'release/')) && github.event_name != 'pull_request' &&
!contains(github.event.head_commit.message, '[skip db]')) ||
contains(github.event.head_commit.message, '[db]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- name: "Run PostgreSQL 13.7 database"
run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
env:
POSTGRES_VERSION: 13.7
- 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
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
repository_postgresql_14_4_tests:
name: "Repository - PostgreSQL 14.4 tests"
runs-on: ubuntu-latest
needs: [prepare]
if: >
(!contains(github.event.head_commit.message, '[skip db]') ||
contains(github.event.head_commit.message, '[latest db]') ||
contains(github.event.head_commit.message, '[db]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- name: "Run PostgreSQL 14.4 database"
run: docker-compose -f ./scripts/ci/docker-compose/docker-compose-db.yaml --profile postgres up -d
env:
POSTGRES_VERSION: 14.4
- 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
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
repository_messaging_tests:
name: Repository - Messaging tests
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]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
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: "Run tests"
run: mvn -B test -pl repository -am -Dtest=CamelRoutesTest,CamelComponentsTest -DfailIfNoTests=false
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
repository_app_context_test_suites:
name: Repository - ${{ matrix.testSuite }}
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:
- testSuite: AppContext01TestSuite
compose-profile: with-transform-core-aio
- testSuite: AppContext02TestSuite
compose-profile: default
- testSuite: AppContext03TestSuite
compose-profile: with-transform-core-aio
- testSuite: AppContext04TestSuite
compose-profile: with-transform-core-aio
- testSuite: AppContext05TestSuite
compose-profile: default
mvn-options: '"-Didentity-service.auth-server-url=http://${HOST_IP}:8999/auth"'
- testSuite: AppContext06TestSuite
compose-profile: with-transform-core-aio
- testSuite: AppContextExtraTestSuite
compose-profile: with-transform-core-aio
- testSuite: MiscContextTestSuite
compose-profile: with-transform-core-aio
- testSuite: SearchTestSuite
compose-profile: default
mvn-options: '-Dindex.subsystem.name=solr6'
- testSuite: MTLSTestSuite
compose-profile: with-mtls-transform-core-aio
mtls: true
mvn-options: '-Dencryption.ssl.keystore.location=${GITHUB_WORKSPACE}/keystores/alfresco/alfresco.keystore -Dencryption.ssl.truststore.location=${GITHUB_WORKSPACE}/keystores/alfresco/alfresco.truststore'
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- name: "Set transformers tag"
run: echo "TRANSFORMERS_TAG=$(mvn help:evaluate -Dexpression=dependency.alfresco-transform-core.version -q -DforceStdout)" >> $GITHUB_ENV
- name: "Generate Keystores and Truststores for Mutual TLS configuration"
if: ${{ matrix.mtls }}
run: |
git clone -b "master" --depth=1 "https://${{ secrets.BOT_GITHUB_USERNAME }}:${{ secrets.BOT_GITHUB_TOKEN }}@github.com/Alfresco/alfresco-ssl-generator.git"
bash ./scripts/ci/generate_keystores.sh
- name: "Set up the environment"
run: |
if [ -e ./scripts/ci/tests/${{ matrix.testSuite }}-setup.sh ]; then
bash ./scripts/ci/tests/${{ matrix.testSuite }}-setup.sh
fi
docker-compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile ${{ matrix.compose-profile }} up -d
- 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 }}
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
tas_tests:
name: ${{ matrix.test-name }}
runs-on: ubuntu-latest
needs: [prepare]
if: >
(((github.ref_name == 'master' || startsWith(github.ref_name, 'release/') || github.event_name == 'pull_request' ) &&
!contains(github.event.head_commit.message, '[skip tas]')) ||
contains(github.event.head_commit.message, '[tas]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
strategy:
fail-fast: false
matrix:
include:
- test-name: "REST API TAS tests part1"
pom-dir: tas-restapi
test-profile: run-restapi-part1
- test-name: "REST API TAS tests part2"
pom-dir: tas-restapi
test-profile: run-restapi-part2
- test-name: "REST API TAS tests part3"
pom-dir: tas-restapi
test-profile: run-restapi-part3
- test-name: "CMIS TAS tests - BROWSER binding"
pom-dir: tas-cmis
test-profile: run-cmis-browser
- test-name: "CMIS TAS tests - ATOM binding"
pom-dir: tas-cmis
test-profile: run-cmis-atom
- test-name: "CMIS TAS tests - WEBSERVICES binding"
pom-dir: tas-cmis
test-profile: run-cmis-webservices
- test-name: "Email TAS tests"
pom-dir: tas-email
- test-name: "WebDAV TAS tests"
pom-dir: tas-webdav
- test-name: "Integration TAS tests"
pom-dir: tas-integration
env:
REQUIRES_LOCAL_IMAGES: true
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: |
bash ./scripts/ci/init.sh
bash ./scripts/ci/build.sh
- name: "Set up the environment"
run: |
${{ env.TAS_SCRIPTS }}/start-compose.sh ${{ env.TAS_ENVIRONMENT }}/docker-compose-minimal+transforms.yml
${{ env.TAS_SCRIPTS }}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
- 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: "Run tests"
id: tests
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
- 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: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
share_services_test_suite:
name: Share Services - ShareServicesTestSuite
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]')
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- name: "Run Postgres 14.4 database"
run: docker-compose -f ./scripts/ci/docker-compose/docker-compose.yaml --profile postgres up -d
- 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
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
ags_postgresql_tests:
name: AGS Integration Tests 0${{ matrix.part }} (PostgreSQL) ${{ matrix.test-name }}
runs-on: ubuntu-latest
needs: [prepare]
if: >
(((github.ref_name == 'master' || startsWith(github.ref_name, 'release/') || github.event_name == 'pull_request' ) &&
!contains(github.event.head_commit.message, '[skip ags]')) ||
contains(github.event.head_commit.message, '[ags]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
strategy:
fail-fast: false
matrix:
part: [1, 2, 3, 4]
env:
REQUIRES_INSTALLED_ARTIFACTS: true
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: |
bash ./scripts/ci/init.sh
bash ./scripts/ci/build.sh
- 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 }}
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
ags_mysql_tests:
name: AGS Integration Tests 0${{ matrix.part }} (MySQL) ${{ matrix.test-name }}
runs-on: ubuntu-latest
needs: [prepare]
if: >
(((github.ref_name == 'master' || startsWith(github.ref_name, 'release/') || github.event_name == 'pull_request' ) &&
!contains(github.event.head_commit.message, '[skip ags]')) ||
contains(github.event.head_commit.message, '[ags on MySQL]')) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
strategy:
fail-fast: false
matrix:
part: [1, 2, 3, 4]
env:
REQUIRES_INSTALLED_ARTIFACTS: true
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: |
bash ./scripts/ci/init.sh
bash ./scripts/ci/build.sh
- 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 }}
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
ags_community_rest_api_tests:
name: "AGS Community Rest API Tests"
runs-on: ubuntu-latest
needs: [prepare]
if: >
(((github.ref_name == 'master' || startsWith(github.ref_name, 'release/') || github.event_name == 'pull_request' ) &&
!contains(github.event.head_commit.message, '[skip ags]') && !contains(github.event.head_commit.message, '[skip tas]')) ||
(contains(github.event.head_commit.message, '[ags]') && contains(github.event.head_commit.message, '[tas]'))) &&
!contains(github.event.head_commit.message, '[skip tests]') &&
!contains(github.event.head_commit.message, '[force]')
env:
REQUIRES_LOCAL_IMAGES: true
steps:
- uses: actions/checkout@v3
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Build"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: |
bash ./scripts/ci/init.sh
bash ./scripts/ci/build.sh
- name: "Set up the environment"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: |
${{ 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: "Test"
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
- name: "Configure AWS credentials"
if: ${{ always() }}
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AGS_AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AGS_AWS_SECRET_ACCESS_KEY }}
aws-region: us-east-1
- name: "Upload artifacts to Amazon S3 bucket"
if: ${{ always() }}
run: |
bash amps/ags/ci/scripts/getLogs.sh
aws s3 cp --acl private alfresco.log s3://ags-travis-artifacts/community/${{ github.run_number }}/AGS-Community-Rest-API-Tests/alfresco.log
aws s3 cp --acl private solr.log s3://ags-travis-artifacts/community/${{ github.run_number }}/AGS-Community-Rest-API-Tests/solr.log
aws s3 cp --acl private ./amps/ags/rm-automation/rm-automation-community-rest-api/target/reports/rm-automation-community-rest-api.log s3://ags-travis-artifacts/community/${{ github.run_number }}/AGS-Community-Rest-API-Tests/rm-automation-community-rest-api.log
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh

79
.github/workflows/master_release.yml vendored Normal file
View File

@@ -0,0 +1,79 @@
name: Master/Release branch workflow
on:
push:
branches:
- master
- release/**
env:
GIT_USERNAME: ${{ secrets.BOT_GITHUB_USERNAME }}
GIT_EMAIL: ${{ secrets.BOT_GITHUB_EMAIL }}
GIT_PASSWORD: ${{ secrets.BOT_GITHUB_TOKEN }}
DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.NEXUS_PASSWORD }}
MAVEN_USERNAME: ${{ secrets.NEXUS_USERNAME }}
QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }}
QUAY_USERNAME: ${{ secrets.QUAY_USERNAME }}
GITHUB_ACTIONS_DEPLOY_TIMEOUT: 60
jobs:
run_ci:
uses: ./.github/workflows/ci.yml
secrets: inherit
push_to_nexus:
name: "Push to Nexus"
runs-on: ubuntu-latest
needs: [run_ci]
if: >
!(failure() || cancelled()) &&
!contains(github.event.head_commit.message, '[no release]') &&
github.event_name != 'pull_request'
steps:
- uses: actions/checkout@v3
with:
persist-credentials: false
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- uses: Alfresco/alfresco-build-tools/.github/actions/configure-git-author@v1.33.0
with:
username: ${{ env.GIT_USERNAME }}
email: ${{ env.GIT_EMAIL }}
global: true
- name: "Release"
timeout-minutes: ${{ fromJSON(env.GITHUB_ACTIONS_DEPLOY_TIMEOUT) }}
run: |
bash scripts/ci/verify_release_tag.sh
bash scripts/ci/maven_release.sh
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh
update_downstream:
name: "Update alfresco-enterprise-repo"
runs-on: ubuntu-latest
needs: [push_to_nexus]
if: >
!(failure() || cancelled()) &&
!contains(github.event.head_commit.message, '[no downstream]') &&
github.event_name != 'pull_request'
steps:
- uses: actions/checkout@v3
with:
persist-credentials: false
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v1.33.0
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v1.33.0
- name: "Init"
run: bash ./scripts/ci/init.sh
- uses: Alfresco/alfresco-build-tools/.github/actions/configure-git-author@v1.33.0
with:
username: ${{ env.GIT_USERNAME }}
email: ${{ env.GIT_EMAIL }}
global: true
- name: "Update downstream"
run: bash ./scripts/ci/update_downstream.sh
env:
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
- name: "Clean Maven cache"
run: bash ./scripts/ci/cleanup_cache.sh

View File

@@ -1,425 +0,0 @@
---
dist: focal
language: java
jdk: openjdk17
services:
- docker
git:
depth: false
quiet: true
cache:
directories:
- ${HOME}/.m2/repository
# the cache can grow constantly
before_cache: bash scripts/travis/cleanup_cache.sh
branches:
only:
- master
- /release\/.*/
- /feature\/.*/
- /fix\/.*/
env:
global:
- TRANSFORMERS_TAG=$(mvn help:evaluate -Dexpression=dependency.alfresco-transform-core.version -q -DforceStdout)
- TAS_SCRIPTS=../alfresco-community-repo/packaging/tests/scripts
- TAS_ENVIRONMENT=./packaging/tests/environment
- LOG_WARN="-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn"
stages:
- name: prepare
if: commit_message !~ /\[skip tests\]/ AND commit_message !~ /\[force[^\]]*\]/
- name: test
if: commit_message !~ /\[skip tests\]/ AND commit_message !~ /\[force[^\]]*\]/
- name: release
if: commit_message !~ /\[no release\]/ AND (branch = master OR branch =~ /release\/.*/) AND type != pull_request AND fork = false
- name: update_downstream
if: commit_message !~ /\[no downstream\]/ AND (branch = master OR branch =~ /release\/.*/) AND type != pull_request AND fork = false
before_install: travis_retry bash scripts/travis/init.sh
install: travis_retry travis_wait 40 bash scripts/travis/build.sh
jobs:
include:
- name: "Prepare"
stage: prepare
install: skip
script: travis_retry travis_wait 80 bash scripts/travis/prepare.sh
- name: "Source Clear Scan (SCA)"
stage: test
if: (branch = master OR branch =~ /release\/.*/) AND type != pull_request
# Run Veracode
install: skip
script: travis_wait 30 bash scripts/travis/source_clear.sh
- name: "Core, Data-Model, Repository - AllUnitTestsSuite - Build and test"
if: commit_message !~ /\[skip repo\]/
install: skip
script:
- travis_retry mvn -B test -pl core,data-model -am -DfailIfNoTests=false
- travis_retry mvn -B test -pl "repository,mmt" -am "-Dtest=AllUnitTestsSuite,AllMmtUnitTestSuite" -DfailIfNoTests=false
- name: "Repository - AppContext01TestSuite"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext01TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - AppContext02TestSuite"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext02TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - AppContext03TestSuite"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext03TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - AppContext04TestSuite"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext04TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - AppContext05TestSuite"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
- mkdir -p "${HOME}/tmp"
- cp repository/src/test/resources/realms/alfresco-realm.json "${HOME}/tmp"
- export HOST_IP=$(hostname -I | cut -f1 -d' ')
- docker run -d -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin -e DB_VENDOR=h2 -p 8999:8080 -e KEYCLOAK_IMPORT=/tmp/alfresco-realm.json -v $HOME/tmp/alfresco-realm.json:/tmp/alfresco-realm.json alfresco/alfresco-identity-service:1.2
script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext05TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco "-Didentity-service.auth-server-url=http://${HOST_IP}:8999/auth"
- name: "Repository - AppContext06TestSuite"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContext06TestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - AppContextExtraTestSuite"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
script: travis_wait 20 mvn -B test -pl repository -am -Dtest=AppContextExtraTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - MiscContextTestSuite"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
script: travis_wait 20 mvn -B test -pl repository -am -Dtest=MiscContextTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Repository - SearchTestSuite"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 mvn -B test -pl repository -am -Dtest=SearchTestSuite -DfailIfNoTests=false -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco -Dindex.subsystem.name=solr6
- name: "Repository - MariaDB 10.2.18 tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
install: skip
before_script:
- docker run -d -p 3307:3306 --name mariadb -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mariadb:10.2.18 --transaction-isolation=READ-COMMITTED --max-connections=300 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 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
- name: "Repository - MariaDB 10.4 tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
install: skip
before_script:
- docker run -d -p 3307:3306 --name mariadb -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mariadb:10.4 --transaction-isolation=READ-COMMITTED --max-connections=300 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 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
- name: "Repository - MariaDB 10.5 tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
install: skip
before_script:
- docker run -d -p 3307:3306 --name mariadb -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mariadb:10.5 --transaction-isolation=READ-COMMITTED --max-connections=300 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 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
- name: "Repository - MariaDB 10.6 tests"
# We run tests on the latest version of MariaDB on pull requests plus the normal master and release branches - ignored on feature branches
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ ) OR commit_message =~ /\[db\]/ OR commit_message =~ /\[latest db\]/
install: skip
before_script:
- docker run -d -p 3307:3306 --name mariadb -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mariadb:10.6 --transaction-isolation=READ-COMMITTED --max-connections=300 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 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
- name: "Repository - MySQL 8 tests"
# We run tests on the latest version of MySQL on pull requests plus the normal master and release branches - ignored on feature branches
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ ) OR commit_message =~ /\[db\]/ OR commit_message =~ /\[latest db\]/
install: skip
before_script:
- docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=alfresco -e MYSQL_USER=alfresco -e MYSQL_DATABASE=alfresco -e MYSQL_PASSWORD=alfresco mysql:8 --transaction-isolation='READ-COMMITTED'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 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
- name: "Repository - PostgreSQL 13.7 tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip db\]/ AND type != pull_request) OR commit_message =~ /\[db\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:13.7 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 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
- name: "Repository - PostgreSQL 14.4 tests"
# We only run DB tests on the latest version of PostgreSQL on feature branches
if: commit_message !~ /\[skip db\]/ OR commit_message =~ /\[db\]/ OR commit_message =~ /\[latest db\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 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
- name: "Repository - Messaging tests"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 mvn -B test -pl repository -am -Dtest=CamelRoutesTest,CamelComponentsTest -DfailIfNoTests=false
- name: "Remote-api - AppContext01TestSuite"
if: commit_message !~ /\[skip repo\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext01TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Remote-api - AppContext02TestSuite"
if: commit_message !~ /\[skip repo\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext02TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Remote-api - AppContext03TestSuite"
if: commit_message !~ /\[skip repo\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext03TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Remote-api - AppContext04TestSuite"
if: commit_message !~ /\[skip repo\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
- docker run -d -p 8090:8090 -e JAVA_OPTS=" -Xms256m -Xmx256m" alfresco/alfresco-transform-core-aio:${TRANSFORMERS_TAG}
script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContext04TestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "Remote-api - AppContextExtraTestSuite"
if: commit_message !~ /\[skip repo\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
- docker run -d -p 61616:61616 -p 5672:5672 alfresco/alfresco-activemq:5.17.1-jre11-rockylinux8
script: travis_wait 20 mvn -B test -pl remote-api -Dtest=AppContextExtraTestSuite -Ddb.driver=org.postgresql.Driver -Ddb.name=alfresco -Ddb.url=jdbc:postgresql://localhost:5433/alfresco -Ddb.username=alfresco -Ddb.password=alfresco
- name: "REST API TAS tests part1"
# TAS tests are generally skipped on feature branches as they will be repeated on the enterprise repo or community packaging builds
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
install: travis_retry travis_wait 40 env REQUIRES_LOCAL_IMAGES=true bash scripts/travis/build.sh
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 60 mvn -B verify -f packaging/tests/tas-restapi/pom.xml -Pall-tas-tests,run-restapi-part1 -Denvironment=default -DrunBugs=false
after_success: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/tas-restapi"
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-restapi"
- name: "REST API TAS tests part2"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
install: travis_retry travis_wait 40 env REQUIRES_LOCAL_IMAGES=true bash scripts/travis/build.sh
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 60 mvn -B verify -f packaging/tests/tas-restapi/pom.xml -Pall-tas-tests,run-restapi-part2 -Denvironment=default -DrunBugs=false
after_success: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/tas-restapi"
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-restapi"
- name: "REST API TAS tests part3"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
install: travis_retry travis_wait 40 env REQUIRES_LOCAL_IMAGES=true bash scripts/travis/build.sh
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 60 mvn -B verify -f packaging/tests/tas-restapi/pom.xml -Pall-tas-tests,run-restapi-part3 -Denvironment=default -DrunBugs=false
after_success: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/tas-restapi"
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-restapi"
- name: "CMIS TAS tests - BROWSER binding"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
install: travis_retry travis_wait 40 env REQUIRES_LOCAL_IMAGES=true bash scripts/travis/build.sh
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 40 mvn -B verify -f packaging/tests/tas-cmis/pom.xml -Pall-tas-tests,run-cmis-browser -Denvironment=default -DrunBugs=false
after_success: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/tas-cmis"
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-cmis"
- name: "CMIS TAS tests - ATOM binding"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
install: travis_retry travis_wait 40 env REQUIRES_LOCAL_IMAGES=true bash scripts/travis/build.sh
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 40 mvn -B verify -f packaging/tests/tas-cmis/pom.xml -Pall-tas-tests,run-cmis-atom -Denvironment=default -DrunBugs=false
after_success: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/tas-cmis"
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-cmis"
- name: "CMIS TAS tests - WEBSERVICES binding"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
install: travis_retry travis_wait 40 env REQUIRES_LOCAL_IMAGES=true bash scripts/travis/build.sh
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal+transforms.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 40 mvn -B verify -f packaging/tests/tas-cmis/pom.xml -Pall-tas-tests,run-cmis-webservices -Denvironment=default -DrunBugs=false
after_success: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/tas-cmis"
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-cmis"
- name: "Email TAS tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
install: travis_retry travis_wait 40 env REQUIRES_LOCAL_IMAGES=true bash scripts/travis/build.sh
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 30 mvn -B verify -f packaging/tests/tas-email/pom.xml -Pall-tas-tests -Denvironment=default -DrunBugs=false
after_success: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/tas-email"
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-email"
- name: "WebDAV TAS tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
install: travis_retry travis_wait 40 env REQUIRES_LOCAL_IMAGES=true bash scripts/travis/build.sh
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
script: travis_wait 30 mvn -B verify -f packaging/tests/tas-webdav/pom.xml -Pall-tas-tests -Denvironment=default -DrunBugs=false
after_success: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/tas-webdav"
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-webdav"
- name: "Integration TAS tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip tas\]/) OR commit_message =~ /\[tas\]/
install: travis_retry travis_wait 40 env REQUIRES_LOCAL_IMAGES=true bash scripts/travis/build.sh
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ${TAS_ENVIRONMENT}/docker-compose-minimal.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8082/alfresco"
- travis_retry travis_wait 40 mvn install -pl :alfresco-community-repo-integration-test -am -DskipTests -Pall-tas-tests
script: travis_wait 30 mvn -B verify -f packaging/tests/tas-integration/pom.xml -Pall-tas-tests -Denvironment=default -DrunBugs=false
after_success: ${TAS_SCRIPTS}/output_tests_run.sh "packaging/tests/tas-integration"
after_failure: ${TAS_SCRIPTS}/output_logs_for_failures.sh "packaging/tests/tas-integration"
- name: "Share Services - ShareServicesTestSuite"
if: commit_message !~ /\[skip repo\]/
install: skip
before_script:
- docker run -d -p 5433:5432 -e POSTGRES_PASSWORD=alfresco -e POSTGRES_USER=alfresco -e POSTGRES_DB=alfresco postgres:14.4 postgres -c 'max_connections=300'
script: travis_wait 20 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
- name: "AGS Unit & Integration Tests 01 (PostgreSQL)"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip ags\]/) OR commit_message =~ /\[ags\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
script: travis_retry travis_wait 80 mvn -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-postgres -PagsAllTestSuitePt1 -f amps/ags/pom.xml ${LOG_WARN}
- name: "AGS Integration Tests 02 (PostgreSQL)"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip ags\]/) OR commit_message =~ /\[ags\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
script: travis_retry travis_wait 80 mvn -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-postgres -PagsAllTestSuitePt2 -f amps/ags/pom.xml ${LOG_WARN}
- name: "AGS Integration Tests 03 (PostgreSQL)"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip ags\]/) OR commit_message =~ /\[ags\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
script: travis_retry travis_wait 80 mvn -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-postgres -PagsAllTestSuitePt3 -f amps/ags/pom.xml ${LOG_WARN}
- name: "AGS Unit & Integration Tests 04 (PostgreSQL)"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip ags\]/) OR commit_message =~ /\[ags\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
script: travis_retry travis_wait 80 mvn -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-postgres -PagsAllTestSuitePt4 -f amps/ags/pom.xml ${LOG_WARN}
- name: "AGS Unit & Integration Tests 01 (MySQL) "
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip ags\]/) OR commit_message =~ /\[ags on MySQL\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
script: travis_retry travis_wait 80 mvn -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-mysql -PagsAllTestSuitePt1 -f amps/ags/pom.xml ${LOG_WARN}
- name: "AGS Integration Tests 02 (MySQL) "
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip ags\]/) OR commit_message =~ /\[ags on MySQL\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
script: travis_retry travis_wait 80 mvn -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-mysql -PagsAllTestSuitePt2 -f amps/ags/pom.xml ${LOG_WARN}
- name: "AGS Integration Tests 03 (MySQL) "
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip ags\]/) OR commit_message =~ /\[ags\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
script: travis_retry travis_wait 80 mvn -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-mysql -PagsAllTestSuitePt3 -f amps/ags/pom.xml ${LOG_WARN}
- name: "AGS Unit & Integration Tests 04 (MySQL) "
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip ags\]/) OR commit_message =~ /\[ags on MySQL\]/
install: travis_retry travis_wait 40 env REQUIRES_INSTALLED_ARTIFACTS=true bash scripts/travis/build.sh
script: travis_retry travis_wait 80 mvn -B verify -Dmaven.javadoc.skip=true -Dmaven.source.skip=true -Pags -Pstart-mysql -PagsAllTestSuitePt4 -f amps/ags/pom.xml ${LOG_WARN}
- name: "AGS Community Rest API Tests"
if: (branch =~ /(release\/.*$|master)/ AND commit_message !~ /\[skip ags\]/ AND commit_message !~ /\[skip tas\]/) OR (commit_message =~ /\[ags\]/ AND commit_message =~ /\[tas\]/)
install: travis_retry travis_wait 40 env REQUIRES_LOCAL_IMAGES=true bash scripts/travis/build.sh
addons:
artifacts:
paths:
- ./amps/ags/rm-automation/rm-automation-community-rest-api/target/reports/rm-automation-community-rest-api.log
- alfresco.log
- solr.log
target_paths: community/${TRAVIS_BUILD_NUMBER}/${TRAVIS_JOB_NAME}
before_script:
- ${TAS_SCRIPTS}/start-compose.sh ./amps/ags/rm-community/rm-community-repo/docker-compose.yml
- ${TAS_SCRIPTS}/wait-for-alfresco-start.sh "http://localhost:8080/alfresco"
- travis_wait 40 mvn -B install -pl :alfresco-governance-services-automation-community-rest-api -am -Pags -Pall-tas-tests -DskipTests
script: travis_wait 40 mvn -B test -pl :alfresco-governance-services-automation-community-rest-api -Dskip.automationtests=false -Pags -Pall-tas-tests
after_script: bash amps/ags/travis/scripts/getLogs.sh
- name: "Push to Nexus"
stage: release
install: skip
before_script: bash scripts/travis/verify_release_tag.sh
script: travis_wait 40 bash scripts/travis/maven_release.sh
- name: "Update alfresco-enterprise-repo"
stage: update_downstream
install: skip
script: bash scripts/travis/update_downstream.sh

View File

@@ -1,6 +1,6 @@
# alfresco-community-repo
[![Build Status](https://travis-ci.com/Alfresco/alfresco-community-repo.svg?branch=master)](https://travis-ci.com/Alfresco/alfresco-community-repo)
[![Build Status](https://github.com/Alfresco/alfresco-community-repo/actions/workflows/master_release.yml/badge.svg?branch=master)](https://github.com/Alfresco/alfresco-community-repo/actions/workflows/master_release.yml)
#### Alfresco Core

View File

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

View File

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

View File

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

View File

@@ -33,7 +33,9 @@ import org.alfresco.rest.rm.community.model.record.Record;
import org.alfresco.rest.v0.RecordsAPI;
import org.alfresco.utility.Utility;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.data.RandomData;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FileType;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
import org.json.JSONObject;
@@ -97,9 +99,10 @@ public class InplaceRecordSearchTests extends BaseRMRestTest {
@Test
public void searchForInplaceRecord() {
// And a document that isn't a record
final String fileName = "File" + RandomData.getRandomAlphanumeric();
uploadedDocbyCollabUser = dataContent.usingSite(privateSite)
.usingUser(siteCollaborator)
.createContent(CMISUtil.DocumentType.TEXT_PLAIN);
.createContent(new FileModel(fileName, FileType.fromName(fileName + "." + CMISUtil.DocumentType.TEXT_PLAIN.extention)));
assertNotNull(uploadedDocbyCollabUser.getNodeRef());

View File

@@ -72,7 +72,7 @@ public class SearchDocumentsV1Test extends BaseRMRestTest
cmisQueryModel.setLanguage("cmis");
RestRequestQueryModel aftsQueryModel = new RestRequestQueryModel();
aftsQueryModel.setQuery("cm:name:*" + SEARCH_TERM);
aftsQueryModel.setQuery("cm:name:*" + SEARCH_TERM + ".txt");
aftsQueryModel.setLanguage("afts");
return new RestRequestQueryModel[][] {
@@ -107,7 +107,7 @@ public class SearchDocumentsV1Test extends BaseRMRestTest
private void waitIndexing() throws Exception
{
RestRequestQueryModel queryType = new RestRequestQueryModel();
queryType.setQuery("cm:name:*" + SEARCH_TERM);
queryType.setQuery("cm:name:*" + SEARCH_TERM + ".txt");
queryType.setLanguage("afts");
Utility.sleep(1000, 80000, () ->
{

View File

@@ -66,7 +66,6 @@ import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanCo
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAspects.CUT_OFF_ASPECT;
import static org.alfresco.rest.rm.community.model.recordcategory.RetentionPeriodProperty.*;
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -84,26 +83,29 @@ public class DispositionScheduleLinkedRecordsTest extends BaseRMRestTest {
@Autowired
private RecordFoldersAPI recordFoldersAPI;
private final static String TEST_PREFIX = generateTestPrefix(DispositionScheduleLinkedRecordsTest.class);
private RecordCategory Category1,catsameLevel1,catsameLevel2;
private RecordCategory Category1;
private RecordCategoryChild CopyCatFolder,folder1,CatFolder,folder2;
private static final String categoryRM3077 = TEST_PREFIX + "RM-3077_manager_sees_me";
private static final String copyCategoryRM3077 = "Copy_of_" + categoryRM3077;
private static final String folderRM3077 = "RM-3077_folder_"+ categoryRM3077;
private static final String copyFolderRM3077 = "Copy_of_" + folderRM3077;
private final String electronicRecord = "RM-2937 electronic 2 record";
private final String folder = TEST_PREFIX + "RM-2937 folder ghosting";
private static final String categoryRecordsRM2526 = TEST_PREFIX + "RM-2526_category_records_immediately";
private static final String category2RecordsRM2526 = TEST_PREFIX + "RM-2526_category_2_records_1_day";
private static final String firstCategoryRM3060 = TEST_PREFIX + "RM-3060_category_record";
private static final String secondCategoryRM3060 = "Copy_of_" + firstCategoryRM3060;
private static final String firstFolderRM3060 = TEST_PREFIX + "RM-3060_folder";
private static final String secondFolderRM3060 = TEST_PREFIX + "RM-3060_disposition_on_Record_Level";
private static final String electronicRecordRM3060 = TEST_PREFIX + "RM-3060_electronic_1_record";
private static final String nonElectronicRecordRM3060 = TEST_PREFIX + "RM-3060_non-electronic_record";
private static final String firstCategoryRM1622 = TEST_PREFIX + "RM-1622_category_record";
private static final String secondCategoryRM1622 = "Copy_of_" + firstCategoryRM1622;;
private static final String firstFolderRM1622 = TEST_PREFIX + "RM-1622_folder";
private static final String electronicRecordRM1622 = TEST_PREFIX + "RM-1622_electronic_1_record";
private static final String secondFolderRM1622 = TEST_PREFIX + "RM-1622_disposition_on_Record_Level";
private static final String TRANSFER_LOCATION = TEST_PREFIX + "RM-3060_transferred_records";
public static final String TRANSFER_TYPE = "rma:transferred";
private FilePlan filePlanModel;
private UserModel rmAdmin, rmManager;
@BeforeClass(alwaysRun = true)
public void setupDispositionScheduleLinkedRecordsTest() {
createRMSiteIfNotExists();
@@ -368,35 +370,35 @@ public class DispositionScheduleLinkedRecordsTest extends BaseRMRestTest {
// create a category with retention applied on records level
RecordCategory catsameLevel1 = getRestAPIFactory().getFilePlansAPI(rmAdmin)
.createRootRecordCategory(RecordCategory.builder().name(firstCategoryRM3060).build(),
RecordCategory.DEFAULT_FILE_PLAN_ALIAS);
.createRootRecordCategory(RecordCategory.builder().name(firstCategoryRM1622).build(),
RecordCategory.DEFAULT_FILE_PLAN_ALIAS);
RecordCategory catsameLevel2 = getRestAPIFactory().getFilePlansAPI(rmAdmin)
.createRootRecordCategory(RecordCategory.builder().name(secondCategoryRM3060).build(),
RecordCategory.DEFAULT_FILE_PLAN_ALIAS);
.createRootRecordCategory(RecordCategory.builder().name(secondCategoryRM1622).build(),
RecordCategory.DEFAULT_FILE_PLAN_ALIAS);
// create retention schedule applied on records for category 1
dispositionScheduleService.createCategoryRetentionSchedule(firstCategoryRM3060, true);
dispositionScheduleService.createCategoryRetentionSchedule(firstCategoryRM1622, true);
// with retain immediately after record creation date and cut 1 day after record creation date
dispositionScheduleService.addCutOffAfterPeriodStep(firstCategoryRM3060, "day|1", DATE_FILED);
dispositionScheduleService.addCutOffAfterPeriodStep(firstCategoryRM1622, "day|1", DATE_FILED);
// create a folder on the category firstCategoryRM3060 with a complete electronic record
RecordCategoryChild firstFolderRecordCategoryChild = createRecordFolder(catsameLevel1.getId(),firstFolderRM3060);
Record firstElectronicRecord = createElectronicRecord(firstFolderRecordCategoryChild.getId(),electronicRecordRM3060);
// create a folder on the category firstCategoryRM1622 with a complete electronic record
RecordCategoryChild firstFolderRecordCategoryChild = createRecordFolder(catsameLevel1.getId(),firstFolderRM1622);
Record firstElectronicRecord = createElectronicRecord(firstFolderRecordCategoryChild.getId(),electronicRecordRM1622);
String elRecordFullName = recordsAPI.getRecordFullName(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(),firstFolderRM3060, electronicRecordRM3060);
getDataUser().getAdminUser().getPassword(),firstFolderRM1622, electronicRecordRM1622);
String elRecordNameNodeRef = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordFullName, "/" + firstCategoryRM3060 + "/" + firstFolderRM3060);
getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordFullName, "/" + firstCategoryRM1622 + "/" + firstFolderRM1622);
recordsAPI.completeRecord(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(), elRecordFullName);
// create a folder on the category secondCategoryRM3060 with a non electronic record
RecordCategoryChild secondFolderRecordCategoryChild = createRecordFolder(catsameLevel2.getId(),secondFolderRM3060);
// create a folder on the category secondCategoryRM1622 with a non electronic record
RecordCategoryChild secondFolderRecordCategoryChild = createRecordFolder(catsameLevel2.getId(),secondFolderRM1622);
String elRecordNameNodeRefs = recordsAPI.getRecordNodeRef(getDataUser().usingAdmin().getAdminUser().getUsername(),
getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordFullName, "/" + firstCategoryRM3060 + "/" + firstFolderRM3060);
getDataUser().usingAdmin().getAdminUser().getPassword(), elRecordFullName, "/" + firstCategoryRM1622 + "/" + firstFolderRM1622);
// link it to the folder in second category through the details page
@@ -404,8 +406,8 @@ public class DispositionScheduleLinkedRecordsTest extends BaseRMRestTest {
recordLists.add(NODE_REF_WORKSPACE_SPACES_STORE + firstElectronicRecord.getId());
linksAPI.linkRecord(getDataUser().getAdminUser().getUsername(),
getDataUser().getAdminUser().getPassword(), HttpStatus.SC_OK,secondCategoryRM3060 + "/" +
secondFolderRM3060, recordLists);
getDataUser().getAdminUser().getPassword(), HttpStatus.SC_OK,secondCategoryRM1622 + "/" +
secondFolderRM1622, recordLists);
// edit disposition date
recordFoldersAPI.postRecordAction(getAdminUser().getUsername(),

View File

@@ -1,7 +1,10 @@
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="TestNG AllTestSuite" configfailurepolicy="continue" verbose="1" time-out="300000">
<test name="restapi">
<listeners>
<listener class-name="org.alfresco.utility.testng.AlphabeticalPriorityInterceptor" />
</listeners>
<test name="restapi" preserve-order="false">
<packages>
<package name="org.alfresco.rest.rm.community.*"/>
</packages>

View File

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

View File

@@ -1,3 +1,3 @@
SOLR6_TAG=2.0.6
SOLR6_TAG=2.0.7-A2
POSTGRES_TAG=14.4
ACTIVEMQ_TAG=5.17.1-jre11-rockylinux8

View File

@@ -1,3 +1,4 @@
ARG BASE_IMAGE
# BUILD STAGE AGS
FROM debian:11-slim AS AGSBUILDER
@@ -12,7 +13,7 @@ RUN unzip -q /build/gs-api-explorer-*.war -d /build/gs-api-explorer && \
chmod -R g-w,o= /build
# ACTUAL IMAGE
FROM alfresco/alfresco-community-repo-base:${image.tag}
FROM ${BASE_IMAGE}
# Alfresco user does not have permissions to modify webapps or configuration. Switch to root.
# The access will be fixed after all operations are done.

View File

@@ -116,8 +116,8 @@ rm.patch.v35.holdNewChildAssocPatch.batchSize=1000
# Permission mapping
# these take a comma separated string of permissions from org.alfresco.service.cmr.security.PermissionService
# read maps to ReadRecords and write to FileRecords
rm.haspermissionmap.read=ReadProperties,ReadChildren
rm.haspermissionmap.write=WriteProperties,AddChildren
rm.haspermissionmap.read=Read
rm.haspermissionmap.write=WriteProperties,AddChildren,ReadContent
#
# Extended auto-version behaviour. If true and other auto-version properties are satisfied, then

View File

@@ -8,13 +8,15 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
<version>20.51</version>
<version>20.127</version>
</parent>
<properties>
<app.amp.client.war.folder>${project.build.directory}/${project.build.finalName}-war</app.amp.client.war.folder>
<image.name>alfresco/alfresco-governance-repository-community-base</image.name>
<base.image>alfresco/alfresco-community-repo-base</base.image>
<scripts.directory>${project.parent.parent.parent.parent.basedir}/scripts</scripts.directory>
</properties>
<dependencies>
@@ -537,9 +539,43 @@
</build>
</profile>
<profile>
<id>build-docker-images</id>
<!-- builds "image:latest" locally -->
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<images>
<image>
<name>${image.name}:${image.tag}</name>
<build>
<args>
<BASE_IMAGE>${base.image}:${image.tag}</BASE_IMAGE>
</args>
<contextDir>${project.basedir}</contextDir>
</build>
</image>
</images>
</configuration>
<executions>
<execution>
<id>build-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>build-docker-images</id>
<!-- builds "image:latest" locally -->
<id>build-multiarch-docker-images</id>
<build>
<plugins>
<plugin>
@@ -548,20 +584,56 @@
<configuration>
<images>
<image>
<name>${image.name}:${image.tag}</name>
<name>${local.registry}/${image.name}:${image.tag}</name>
<build>
<buildx>
<platforms>
<platform>linux/amd64</platform>
<platform>linux/arm64</platform>
</platforms>
<builderName>${builder.name}</builderName>
</buildx>
<contextDir>${project.basedir}</contextDir>
<args>
<BASE_IMAGE>${local.registry}/${base.image}:${image.tag}</BASE_IMAGE>
</args>
</build>
</image>
</images>
</configuration>
<executions>
<execution>
<id>build-image</id>
<id>build-push-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<executions>
<execution>
<id>prepare-buildx</id>
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${scripts.directory}/prepare_buildx.sh</executable>
<arguments>
<argument>${builder.name}</argument>
<argument>${image.registry}</argument>
<argument>${image.name}</argument>
<argument>${image.tag}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
@@ -578,12 +650,37 @@
<images>
<image>
<!-- Quay image -->
<name>${image.name}:${image.tag}</name>
<registry>${image.registry}</registry>
<name>${image.registry}/${image.name}:${image.tag}</name>
<build>
<buildx>
<platforms>
<platform>linux/amd64</platform>
<platform>linux/arm64</platform>
</platforms>
<builderName>${builder.name}</builderName>
</buildx>
<args>
<BASE_IMAGE>${local.registry}/${base.image}:${image.tag}</BASE_IMAGE>
</args>
<contextDir>${project.basedir}</contextDir>
</build>
</image>
<image>
<!-- DockerHub image -->
<name>${image.name}:${image.tag}</name>
<build>
<buildx>
<platforms>
<platform>linux/amd64</platform>
<platform>linux/arm64</platform>
</platforms>
<builderName>${builder.name}</builderName>
</buildx>
<args>
<BASE_IMAGE>${local.registry}/${base.image}:${image.tag}</BASE_IMAGE>
</args>
<contextDir>${project.basedir}</contextDir>
</build>
</image>
</images>
</configuration>
@@ -598,6 +695,28 @@
</execution>
</executions>
</plugin>
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<executions>
<execution>
<id>prepare-buildx</id>
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${scripts.directory}/prepare_buildx.sh</executable>
<arguments>
<argument>${builder.name}</argument>
<argument>${image.registry}</argument>
<argument>${image.name}</argument>
<argument>${image.tag}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>20.51</version>
<version>20.127</version>
</parent>
<modules>
@@ -15,7 +15,7 @@
</modules>
<!-- When adding a new AMP, create a profile for it here to add the module. The AMPS environment variable may
then be used in aliases to optionally build it. The profile will however need to be added to the Travis
then be used in aliases to optionally build it. The profile will however need to be added to the Github Actions
build scripts. The share-services AMP is build by default as it is very fast. -->
<profiles>
<profile>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>20.51</version>
<version>20.127</version>
</parent>
<properties>
@@ -121,12 +121,6 @@
<version>${dependency.webscripts.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>

View File

@@ -241,7 +241,7 @@ var Filters =
filterData = filterData.slice(0, -1);
}
filterQuery = this.constructPathQuery(parsedArgs);
filterParams.query = filterQuery + " +PATH:\"/cm:generalclassifiable" + Filters.iso9075EncodePath(filterData) + "/member\"";
filterParams.query = filterQuery + " +PATH:\"/cm:categoryRoot/cm:generalclassifiable" + Filters.iso9075EncodePath(filterData) + "/member\"";
break;
case "aspect":

View File

@@ -230,7 +230,7 @@ var Filters =
filterData = filterData.slice(0, -1);
}
filterQuery = this.constructPathQuery(parsedArgs);
filterParams.query = filterQuery + " +PATH:\"/cm:generalclassifiable" + Filters.iso9075EncodePath(filterData) + "/member\"";
filterParams.query = filterQuery + " +PATH:\"/cm:categoryRoot/cm:generalclassifiable" + Filters.iso9075EncodePath(filterData) + "/member\"";
break;
default: // "path"

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>20.51</version>
<version>20.127</version>
</parent>
<dependencies>
@@ -137,6 +137,10 @@
<artifactId>commons-dbcp2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
<build>

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2023 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.httpclient;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import org.alfresco.error.AlfrescoRuntimeException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
public class HttpClient4Factory
{
protected static final String TLS_PROTOCOL = "TLS";
protected static final String HTTPS_PROTOCOL = "https";
protected static final String HTTP_TARGET_HOST = "http.target_host";
protected static final String TLS_V_1_2 = "TLSv1.2";
protected static final String TLS_V_1_3 = "TLSv1.3";
private static SSLContext createSSLContext(HttpClientConfig config)
{
KeyManager[] keyManagers = config.getKeyStore().createKeyManagers();
TrustManager[] trustManagers = config.getTrustStore().createTrustManagers();
try
{
SSLContext sslcontext = SSLContext.getInstance(TLS_PROTOCOL);
sslcontext.init(keyManagers, trustManagers, null);
return sslcontext;
}
catch(Throwable e)
{
throw new AlfrescoRuntimeException("Unable to create SSL context", e);
}
}
public static CloseableHttpClient createHttpClient(HttpClientConfig config)
{
return createHttpClient(config, null);
}
public static CloseableHttpClient createHttpClient(HttpClientConfig config, HttpClientConnectionManager connectionManager)
{
HttpClientBuilder clientBuilder = HttpClients.custom();
if(config.isMTLSEnabled())
{
clientBuilder.addInterceptorFirst((HttpRequestInterceptor) (request, context) -> {
if (!((HttpHost) context.getAttribute(HTTP_TARGET_HOST)).getSchemeName().equals(HTTPS_PROTOCOL))
{
String msg = "mTLS is enabled but provided URL does not use a secured protocol";
throw new HttpClientException(msg);
}
});
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
createSSLContext(config),
new String[] { TLS_V_1_2, TLS_V_1_3 },
null,
config.isHostnameVerificationDisabled() ? new NoopHostnameVerifier() : SSLConnectionSocketFactory.getDefaultHostnameVerifier());
clientBuilder.setSSLSocketFactory(sslConnectionSocketFactory);
}
if(connectionManager != null)
{
clientBuilder.setConnectionManager(connectionManager);
}
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(config.getConnectionTimeout())
.setSocketTimeout(config.getSocketTimeout())
.setConnectionRequestTimeout(config.getConnectionRequestTimeout())
.build();
clientBuilder.setDefaultRequestConfig(requestConfig);
clientBuilder.setMaxConnTotal(config.getMaxTotalConnections());
clientBuilder.setMaxConnPerRoute(config.getMaxHostConnections());
clientBuilder.setRetryHandler(new StandardHttpRequestRetryHandler(5, false));
return clientBuilder.build();
}
}

View File

@@ -0,0 +1,202 @@
/*
* Copyright (C) 2023 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.httpclient;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.stream.Collectors;
import org.alfresco.encryption.AlfrescoKeyStore;
import org.alfresco.encryption.AlfrescoKeyStoreImpl;
import org.alfresco.encryption.KeyResourceLoader;
import org.alfresco.encryption.ssl.SSLEncryptionParameters;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class HttpClientConfig
{
private static final String HTTPCLIENT_CONFIG = "httpclient.config.";
protected static final Log LOGGER = LogFactory.getLog(HttpClientConfig.class);
private Properties properties;
private String serviceName;
private SSLEncryptionParameters sslEncryptionParameters;
private KeyResourceLoader keyResourceLoader;
private AlfrescoKeyStore keyStore;
private AlfrescoKeyStore trustStore;
private Map<String, String> config;
public void setProperties(Properties properties)
{
this.properties = properties;
}
public void setServiceName(String serviceName)
{
this.serviceName = serviceName;
}
public void setSslEncryptionParameters(SSLEncryptionParameters sslEncryptionParameters)
{
this.sslEncryptionParameters = sslEncryptionParameters;
}
public void setKeyResourceLoader(KeyResourceLoader keyResourceLoader)
{
this.keyResourceLoader = keyResourceLoader;
}
public AlfrescoKeyStore getKeyStore()
{
return keyStore;
}
public AlfrescoKeyStore getTrustStore()
{
return trustStore;
}
public void init()
{
this.keyStore = new AlfrescoKeyStoreImpl(sslEncryptionParameters.getKeyStoreParameters(), keyResourceLoader);
this.trustStore = new AlfrescoKeyStoreImpl(sslEncryptionParameters.getTrustStoreParameters(), keyResourceLoader);
config = retrieveConfig(serviceName);
checkUnsupportedProperties(config);
}
/**
* Method used for retrieving HttpClient config from Global Properties
* @param serviceName name of used service
* @return map of properties
*/
private Map<String, String> retrieveConfig(String serviceName)
{
return properties.keySet().stream()
.filter(key -> key instanceof String)
.map(Object::toString)
.filter(key -> key.startsWith(HTTPCLIENT_CONFIG + serviceName))
.collect(Collectors.toMap(
key -> key.replace(HTTPCLIENT_CONFIG + serviceName + ".", ""),
key -> properties.getProperty(key, null)));
}
private void checkUnsupportedProperties(Map<String, String> config)
{
config.keySet().stream()
.filter(propertyName -> !HttpClientPropertiesEnum.isPropertyNameSupported(propertyName))
.forEach(propertyName -> LOGGER.warn(String.format("For service [%s], an unsupported property [%s] is set", serviceName, propertyName)));
}
private Integer getIntegerProperty(HttpClientPropertiesEnum property)
{
return Integer.parseInt(extractValueFromConfig(property).orElse("0"));
}
private Boolean getBooleanProperty(HttpClientPropertiesEnum property)
{
return Boolean.parseBoolean(extractValueFromConfig(property).orElse("false"));
}
private Optional<String> extractValueFromConfig(HttpClientPropertiesEnum property)
{
Optional<String> optionalProperty = Optional.ofNullable(config.get(property.name));
if(property.isRequired && optionalProperty.isEmpty())
{
String msg = String.format("Required property: '%s' is empty.", property.name);
throw new HttpClientException(msg);
}
return optionalProperty;
}
public Integer getConnectionTimeout()
{
return getIntegerProperty(HttpClientPropertiesEnum.CONNECTION_REQUEST_TIMEOUT);
}
public Integer getSocketTimeout()
{
return getIntegerProperty(HttpClientPropertiesEnum.SOCKET_TIMEOUT);
}
public Integer getConnectionRequestTimeout()
{
return getIntegerProperty(HttpClientPropertiesEnum.CONNECTION_REQUEST_TIMEOUT);
}
public Integer getMaxTotalConnections()
{
return getIntegerProperty(HttpClientPropertiesEnum.MAX_TOTAL_CONNECTIONS);
}
public Integer getMaxHostConnections()
{
return getIntegerProperty(HttpClientPropertiesEnum.MAX_HOST_CONNECTIONS);
}
public Boolean isMTLSEnabled()
{
return getBooleanProperty(HttpClientPropertiesEnum.MTLS_ENABLED);
}
public boolean isHostnameVerificationDisabled()
{
return getBooleanProperty(HttpClientPropertiesEnum.HOSTNAME_VERIFICATION_DISABLED);
}
private enum HttpClientPropertiesEnum
{
CONNECTION_TIMEOUT("connectionTimeout", true),
SOCKET_TIMEOUT("socketTimeout", true),
CONNECTION_REQUEST_TIMEOUT("connectionRequestTimeout", true),
MAX_TOTAL_CONNECTIONS("maxTotalConnections", true),
MAX_HOST_CONNECTIONS("maxHostConnections", true),
HOSTNAME_VERIFICATION_DISABLED("hostnameVerificationDisabled", false),
MTLS_ENABLED("mTLSEnabled", true);
private final String name;
private final Boolean isRequired;
HttpClientPropertiesEnum(String propertyName, Boolean isRequired)
{
this.name = propertyName;
this.isRequired = isRequired;
}
private static final List<String> supportedProperties = new ArrayList<>();
static {
for (HttpClientPropertiesEnum property : HttpClientPropertiesEnum.values()) {
supportedProperties.add(property.name);
}
}
public static boolean isPropertyNameSupported(String propertyName) {
return supportedProperties.contains(propertyName);
}
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2023 Alfresco Software Limited.
*
* This file is part of Alfresco
*
* 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/>.
*/
package org.alfresco.httpclient;
import org.alfresco.error.AlfrescoRuntimeException;
public class HttpClientException extends AlfrescoRuntimeException
{
public HttpClientException(String msgId)
{
super(msgId);
}
}

View File

@@ -45,6 +45,13 @@ public class ListBackedPagingResults<R> implements PagingResults<R>
size = list.size();
hasMore = false;
}
public ListBackedPagingResults(List<R> list, boolean hasMore)
{
this(list);
this.hasMore = hasMore;
}
public ListBackedPagingResults(List<R> list, PagingRequest paging)
{
// Excerpt

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>20.51</version>
<version>20.127</version>
</parent>
<properties>

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Data model classes
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -51,6 +51,18 @@ public class MLText extends HashMap<Locale, String>
{
private static final long serialVersionUID = -3696135175650511841L;
/**
* Returns default locale used by the {@link MLText} implementation
*
* @see I18NUtil#getLocale()
*
* @return default locale
*/
public static Locale getDefaultLocale()
{
return I18NUtil.getLocale();
}
public MLText()
{
super(3, 0.75F);
@@ -61,13 +73,13 @@ public class MLText extends HashMap<Locale, String>
*
* @param value the value for the current default locale
*
* @see I18NUtil#getLocale()
* @see #getDefaultLocale()
* @see #MLText(Locale, String)
* @see #getDefaultValue()
*/
public MLText(String value)
{
this(I18NUtil.getLocale(), value);
this(getDefaultLocale(), value);
}
/**
@@ -124,7 +136,7 @@ public class MLText extends HashMap<Locale, String>
/**
* Retrieves a default value from the set of available locales.<br/>
*
* @see I18NUtil#getLocale()
* @see #getDefaultLocale()
* @see #getClosestValue(Locale)
*/
public String getDefaultValue()
@@ -135,7 +147,7 @@ public class MLText extends HashMap<Locale, String>
return null;
}
// There is some hope of getting a match
Locale locale = I18NUtil.getLocale();
Locale locale = getDefaultLocale();
return getClosestValue(locale);
}
@@ -168,7 +180,7 @@ public class MLText extends HashMap<Locale, String>
if (match == null)
{
// No close matches for the locale - go for the default locale
locale = I18NUtil.getLocale();
locale = getDefaultLocale();
match = I18NUtil.getNearestLocale(locale, options);
if (match == null)
{

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
# Fetch image based on Tomcat 9.0, Java 17 and Rocky Linux 8
# More infos about this image: https://github.com/Alfresco/alfresco-docker-base-tomcat
FROM alfresco/alfresco-base-tomcat:tomcat9-jre17-rockylinux8-202209261711
FROM alfresco/alfresco-base-tomcat:tomcat9-jre17-rockylinux8-202303081618
# Set default docker_context.
ARG resource_path=target
@@ -65,7 +65,7 @@ RUN sed -i -e "s_appender.rolling.fileName\=alfresco.log_appender.rolling.fileNa
RUN yum install -y fontconfig-2.13.1-4.el8 \
dejavu-fonts-common-2.35-7.el8 \
fontpackages-filesystem-1.44-22.el8 \
freetype-2.9.1-4.el8_3.1 \
freetype-2.9.1-9.el8 \
libpng-1.6.34-5.el8 \
dejavu-sans-fonts-2.35-7.el8 && \
yum clean all

View File

@@ -7,11 +7,12 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>20.51</version>
<version>20.127</version>
</parent>
<properties>
<image.name>alfresco/alfresco-community-repo-base</image.name>
<scripts.directory>${project.parent.parent.basedir}/scripts</scripts.directory>
</properties>
<build>
@@ -156,6 +157,67 @@
</build>
</profile>
<profile>
<id>build-multiarch-docker-images</id>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<images>
<image>
<name>${local.registry}/${image.name}:${image.tag}</name>
<build>
<buildx>
<platforms>
<platform>linux/amd64</platform>
<platform>linux/arm64</platform>
</platforms>
<builderName>${builder.name}</builderName>
</buildx>
<contextDir>${project.basedir}</contextDir>
</build>
</image>
</images>
</configuration>
<executions>
<execution>
<id>build-push-image</id>
<phase>package</phase>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<executions>
<execution>
<id>prepare-buildx</id>
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>${scripts.directory}/prepare_buildx.sh</executable>
<arguments>
<argument>${builder.name}</argument>
<argument>${image.registry}</argument>
<argument>${image.name}</argument>
<argument>${image.tag}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>push-docker-images</id>
<!-- publishes "image:latest" on Quay & DockerHub -->
@@ -168,12 +230,29 @@
<images>
<!-- Quay image -->
<image>
<name>${image.name}:${image.tag}</name>
<registry>${image.registry}</registry>
<name>${image.registry}/${image.name}:${image.tag}</name>
<build>
<buildx>
<platforms>
<platform>linux/amd64</platform>
<platform>linux/arm64</platform>
</platforms>
</buildx>
<contextDir>${project.basedir}</contextDir>
</build>
</image>
<!-- DockerHub image -->
<image>
<name>${image.name}:${image.tag}</name>
<build>
<buildx>
<platforms>
<platform>linux/amd64</platform>
<platform>linux/arm64</platform>
</platforms>
</buildx>
<contextDir>${project.basedir}</contextDir>
</build>
</image>
</images>
</configuration>

View File

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

View File

@@ -1,3 +1,3 @@
SOLR6_TAG=2.0.6
SOLR6_TAG=2.0.7-A2
POSTGRES_TAG=14.4
ACTIVEMQ_TAG=5.17.1-jre11-rockylinux8

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>20.51</version>
<version>20.127</version>
</parent>
<organization>

View File

@@ -4,8 +4,6 @@ import org.alfresco.utility.data.AisToken;
import org.alfresco.utility.data.auth.DataAIS;
import org.alfresco.utility.model.UserModel;
import org.apache.chemistry.opencmis.commons.SessionParameter;
import org.keycloak.authorization.client.util.HttpResponseException;
import org.keycloak.representations.AccessTokenResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -86,9 +84,9 @@ public class AuthParameterProviderFactory
parameters.put(SessionParameter.OAUTH_REFRESH_TOKEN, aisToken.getRefreshToken());
parameters.put(SessionParameter.OAUTH_EXPIRATION_TIMESTAMP, String.valueOf(System.currentTimeMillis()
+ (aisToken.getExpiresIn() * 1000))); // getExpiresIn is in seconds
parameters.put(SessionParameter.OAUTH_TOKEN_ENDPOINT, cmisProperties.aisProperty().getAdapterConfig().getAuthServerUrl()
parameters.put(SessionParameter.OAUTH_TOKEN_ENDPOINT, cmisProperties.aisProperty().getAuthServerUrl()
+ "/realms/alfresco/protocol/openid-connect/token");
parameters.put(SessionParameter.OAUTH_CLIENT_ID, cmisProperties.aisProperty().getAdapterConfig().getResource());
parameters.put(SessionParameter.OAUTH_CLIENT_ID, cmisProperties.aisProperty().getResource());
return parameters;
}
@@ -110,10 +108,10 @@ public class AuthParameterProviderFactory
// Attempt to get an access token for userModel from AIS
aisToken = dataAIS.perform().getAccessToken(userModel);
}
catch (HttpResponseException e)
catch (AssertionError e)
{
// Trying to authenticate with invalid user credentials so return an invalid access token
if (e.getStatusCode() == 401)
if (e.getMessage().contains("invalid_grant"))
{
STEP(String.format("%s Invalid user credentials were provided %s:%s. Using invalid token for reqest.",
STEP_PREFIX, userModel.getUsername(), userModel.getPassword()));

View File

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

View File

@@ -9,7 +9,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>20.51</version>
<version>20.127</version>
</parent>
<developers>
@@ -95,7 +95,6 @@
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>${dependency.jakarta-json-path.version}</version>
</dependency>
</dependencies>

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>20.51</version>
<version>20.127</version>
</parent>
<properties>
@@ -165,14 +165,14 @@
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>3.0.12</version>
<version>3.0.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-json-->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-json</artifactId>
<version>3.0.12</version>
<version>3.0.16</version>
</dependency>
<dependency>

View File

@@ -30,7 +30,6 @@ import static org.alfresco.utility.report.log.Step.STEP;
import org.alfresco.utility.data.AisToken;
import org.alfresco.utility.data.auth.DataAIS;
import org.alfresco.utility.model.UserModel;
import org.keycloak.authorization.client.util.HttpResponseException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -86,12 +85,11 @@ public class RestAisAuthentication
// Attempt to get an access token for userModel from AIS
aisToken = dataAIS.perform().getAccessToken(userModel);
}
catch (HttpResponseException e)
catch (AssertionError e)
{
// Trying to authenticate with invalid user credentials or disabled
// user so return an invalid access token
String httpResponse = new String(e.getBytes());
if (e.getStatusCode() == 401 || httpResponse.contains(USER_DISABLED_MSG))
if (e.getMessage().contains("invalid_grant"))
{
STEP(String.format("%s User disabled or invalid user credentials were provided %s:%s. Using invalid token for request.", STEP_PREFIX,
userModel.getUsername(), userModel.getPassword()));

View File

@@ -333,6 +333,22 @@ public class ModelAssertion<T>
return (T) model;
}
public T containsOnce(String value)
{
final String fieldContent = fieldValue.toString();
final int i = fieldContent.indexOf(value);
if (i == -1)
{
Assert.fail(errorMessage("does NOT contain at all the expected value: " + value + ", Current Value: " + fieldValue.toString()));
}
if (i != fieldContent.lastIndexOf(value))
{
Assert.fail(errorMessage("contains more than one expected value: " + value + ", Current Value: " + fieldValue.toString()));
}
return (T) model;
}
public T notContains(String value)
{
if (fieldValue.toString().contains(value))

View File

@@ -30,7 +30,10 @@ import static org.alfresco.utility.report.log.Step.STEP;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import org.alfresco.rest.core.IRestModelsCollection;
import org.alfresco.utility.exception.TestConfigurationException;
@@ -117,7 +120,7 @@ public class ModelsCollectionAssertion<C>
return (C) modelCollection;
}
@SuppressWarnings("unchecked")
@SuppressWarnings("unchecked")
public C entriesListDoesNotContain(String key, String value)
{
boolean exist = false;
@@ -143,6 +146,53 @@ public class ModelsCollectionAssertion<C>
return (C) modelCollection;
}
public C entrySetContains(String key, String... expectedValues)
{
return entrySetContains(key, Arrays.stream(expectedValues).collect(Collectors.toSet()));
}
@SuppressWarnings("unchecked")
public C entrySetContains(String key, Collection<String> expectedValues)
{
Collection<String> actualValues = ((List<Model>) modelCollection.getEntries()).stream()
.map(model -> extractValueAsString(model, key))
.collect(Collectors.toSet());
Assert.assertTrue(actualValues.containsAll(expectedValues), String.format("Entry with key: \"%s\" is expected to contain values: %s, but actual values are: %s",
key, expectedValues, actualValues));
return (C) modelCollection;
}
@SuppressWarnings("unchecked")
public C entrySetMatches(String key, Collection<String> expectedValues)
{
Collection<String> actualValues = ((List<Model>) modelCollection.getEntries()).stream()
.map(model -> extractValueAsString(model, key))
.collect(Collectors.toSet());
Assert.assertEqualsNoOrder(actualValues, expectedValues, String.format("Entry with key: \"%s\" is expected to match values: %s, but actual values are: %s",
key, expectedValues, actualValues));
return (C) modelCollection;
}
private String extractValueAsString(Model model, String key)
{
String fieldValue;
Object modelObject = loadModel(model);
try {
ObjectMapper mapper = new ObjectMapper();
String jsonInString = mapper.writeValueAsString(modelObject);
fieldValue = JsonPath.with(jsonInString).get(key);
} catch (Exception e) {
throw new TestConfigurationException(String.format(
"You try to assert field [%s] that doesn't exist in class: [%s]. Exception: %s, Please check your code!",
key, getClass().getCanonicalName(), e.getMessage()));
}
return fieldValue;
}
@SuppressWarnings("unchecked")
public C entriesListDoesNotContain(String key)
{

View File

@@ -1,5 +1,7 @@
package org.alfresco.rest.model;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.alfresco.rest.core.IRestModel;
import org.alfresco.utility.model.TestModel;
@@ -25,16 +27,62 @@ public class RestCategoryLinkBodyModel extends TestModel implements IRestModel<R
*/
@JsonProperty(required = true)
private String id;
private String categoryId;
public String getId()
public String getCategoryId()
{
return this.id;
return categoryId;
}
public void setId(String id)
public void setCategoryId(String categoryId)
{
this.id = id;
}
this.categoryId = categoryId;
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
RestCategoryLinkBodyModel that = (RestCategoryLinkBodyModel) o;
return Objects.equals(categoryId, that.categoryId);
}
@Override
public int hashCode()
{
return Objects.hash(categoryId);
}
@Override
public String toString()
{
return "RestCategoryLinkBodyModel{" + "categoryId='" + categoryId + '\'' + '}';
}
public static Builder builder()
{
return new Builder();
}
public static class Builder
{
private String categoryId;
public Builder categoryId(String categoryId)
{
this.categoryId = categoryId;
return this;
}
public RestCategoryLinkBodyModel create()
{
final RestCategoryLinkBodyModel categoryLink = new RestCategoryLinkBodyModel();
categoryLink.setCategoryId(categoryId);
return categoryLink;
}
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -27,6 +27,8 @@ package org.alfresco.rest.model;
import static org.alfresco.utility.report.log.Step.STEP;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.alfresco.rest.core.IRestModel;
@@ -73,4 +75,65 @@ public class RestTagModel extends TagModel implements IRestModel<RestTagModel>
this.count = count;
}
@Override
public boolean equals(Object o)
{
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
RestTagModel tagModel = (RestTagModel) o;
return Objects.equals(id, tagModel.id) && Objects.equals(tag, tagModel.tag) && Objects.equals(count, tagModel.count);
}
@Override
public int hashCode()
{
return Objects.hash(id, tag, count);
}
@Override
public String toString()
{
return "RestTagModel{" + "id='" + id + ", tag='" + tag + '\'' + ", count=" + count + '\'' + '}';
}
public static Builder builder()
{
return new Builder();
}
public static class Builder
{
private String id;
private String tag;
private Integer count;
public Builder id(String id)
{
this.id = id;
return this;
}
public Builder tag(String tag)
{
this.tag = tag;
return this;
}
public Builder count(Integer count)
{
this.count = count;
return this;
}
public RestTagModel create()
{
final RestTagModel tag = new RestTagModel();
tag.setId(id);
tag.setTag(this.tag);
tag.setCount(count);
return tag;
}
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -26,6 +26,7 @@
package org.alfresco.rest.requests;
import static org.alfresco.rest.core.JsonBodyGenerator.arrayToJson;
import static org.alfresco.rest.requests.RuleSettings.IS_INHERITANCE_ENABLED;
import static org.springframework.http.HttpMethod.PUT;
@@ -33,6 +34,7 @@ import javax.json.JsonArrayBuilder;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import io.restassured.http.ContentType;
import org.alfresco.rest.core.JsonBodyGenerator;
@@ -41,6 +43,9 @@ import org.alfresco.rest.core.RestResponse;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.exception.JsonToModelConversionException;
import org.alfresco.rest.model.RestActionDefinitionModelsCollection;
import org.alfresco.rest.model.RestCategoryLinkBodyModel;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.model.RestCategoryModelsCollection;
import org.alfresco.rest.model.RestCommentModel;
import org.alfresco.rest.model.RestCommentModelsCollection;
import org.alfresco.rest.model.RestNodeAssocTargetModel;
@@ -537,8 +542,8 @@ public class Node extends ModelRequest<Node>
renditionId);
RestResponse response = restWrapper.process(request);
int retry = 0;
//Multiplied by '4' because AI rendition test cases need more time (~30 seconds) - see ACS-2158
while (Integer.valueOf(response.getStatusCode()).equals(HttpStatus.NOT_FOUND.value()) && retry < (4 * Utility.retryCountSeconds))
//Multiplied by '8' because AI rendition test cases need more time (~30 seconds) - see ACS-2158
while (!Integer.valueOf(response.getStatusCode()).equals(HttpStatus.OK.value()) && retry < (8 * Utility.retryCountSeconds))
{
Utility.waitToLoopTime(1);
response = restWrapper.process(request);
@@ -1106,4 +1111,50 @@ public class Node extends ModelRequest<Node>
RestRequest request = RestRequest.requestWithBody(HttpMethod.POST, body.toJson(), "nodes/{nodeId}/rule-executions", repoModel.getNodeRef());
return restWrapper.processModel(RestRuleExecutionModel.class, request);
}
/**
* Get linked categories performing GET cal on "/nodes/{nodeId}/category-links"
*
* @return categories which are linked from content
*/
public RestCategoryModelsCollection getLinkedCategories()
{
RestRequest request = RestRequest.simpleRequest(HttpMethod.GET, "nodes/{nodeId}/category-links", repoModel.getNodeRef());
return restWrapper.processModels(RestCategoryModelsCollection.class, request);
}
/**
* Link content to category performing POST call on "/nodes/{nodeId}/category-links"
*
* @param categoryLink - contains category ID
* @return linked to category
*/
public RestCategoryModel linkToCategory(RestCategoryLinkBodyModel categoryLink)
{
RestRequest request = RestRequest.requestWithBody(HttpMethod.POST, categoryLink.toJson(), "nodes/{nodeId}/category-links", repoModel.getNodeRef());
return restWrapper.processModel(RestCategoryModel.class, request);
}
/**
* Link content to many categories performing POST call on "/nodes/{nodeId}/category-links"
*
* @param categoryLinks - contains categories IDs
* @return linked to categories
*/
public RestCategoryModelsCollection linkToCategories(List<RestCategoryLinkBodyModel> categoryLinks)
{
RestRequest request = RestRequest.requestWithBody(HttpMethod.POST, arrayToJson(categoryLinks), "nodes/{nodeId}/category-links", repoModel.getNodeRef());
return restWrapper.processModels(RestCategoryModelsCollection.class, request);
}
/**
* Unlink content from a category performing a DELETE call on "nodes/{nodeId}/category-links/{categoryId}"
*
* @param categoryId the id of the category to be unlinked from content
*/
public void unlinkFromCategory(String categoryId)
{
RestRequest request = RestRequest.simpleRequest(HttpMethod.DELETE, "nodes/{nodeId}/category-links/{categoryId}", repoModel.getNodeRef(), categoryId);
restWrapper.processEmptyModel(request);
}
}

View File

@@ -82,4 +82,15 @@ public class Tags extends ModelRequest<Tags>
return restWrapper.processModel(RestTagModel.class, request);
}
/**
* Delete tag.
* - DELETE /tags/{tagId}
*/
public void deleteTag()
{
RestRequest request = RestRequest.
simpleRequest(HttpMethod.DELETE, "/tags/{tagId}", tag.getId());
restWrapper.processEmptyModel(request);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* alfresco-tas-restapi
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,6 +25,12 @@
*/
package org.alfresco.rest.requests.coreAPI;
import static org.alfresco.rest.core.JsonBodyGenerator.arrayToJson;
import java.util.List;
import io.restassured.RestAssured;
import org.alfresco.rest.core.RestRequest;
import org.alfresco.rest.core.RestWrapper;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.model.RestDownloadsModel;
@@ -49,8 +55,7 @@ import org.alfresco.rest.requests.Trashcan;
import org.alfresco.utility.model.RepoTestModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.UserModel;
import io.restassured.RestAssured;
import org.springframework.http.HttpMethod;
/**
* Defines the entire Rest Core API
@@ -172,6 +177,30 @@ public class RestCoreAPI extends ModelRequest<RestCoreAPI>
return new Networks(restWrapper);
}
/**
* Create a single orphan tag.
*
* @param tag Tag model to create.
* @return Created tag.
*/
public RestTagModel createSingleTag(RestTagModel tag)
{
RestRequest request = RestRequest.requestWithBody(HttpMethod.POST, tag.toJson(), "tags/");
return restWrapper.processModel(RestTagModel.class, request);
}
/**
* Create several orphan tags in one request.
*
* @param tags Tags models to create.
* @return Created tags.
*/
public RestTagModelsCollection createTags(List<RestTagModel> tags)
{
RestRequest request = RestRequest.requestWithBody(HttpMethod.POST, arrayToJson(tags), "tags/");
return restWrapper.processModels(RestTagModelsCollection.class, request);
}
public Tags usingTag(RestTagModel tag)
{
return new Tags(tag, restWrapper);

View File

@@ -0,0 +1,207 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2023 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.categories;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.OK;
import static org.testng.Assert.assertTrue;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.model.RestCategoryModelsCollection;
import org.alfresco.utility.Utility;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestGroup;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class CategoriesCountTests extends CategoriesRestTest
{
private RestCategoryModel categoryLinkedWithFolder;
private RestCategoryModel categoryLinkedWithFile;
private RestCategoryModel categoryLinkedWithBoth;
private RestCategoryModel notLinkedCategory;
@BeforeClass(alwaysRun = true)
public void dataPreparation() throws Exception
{
STEP("Create user and site");
user = dataUser.createRandomTestUser();
SiteModel site = dataSite.usingUser(user).createPublicRandomSite();
STEP("Create a folder, file in it and few categories");
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
FileModel file = dataContent.usingUser(user).usingResource(folder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
categoryLinkedWithFolder = prepareCategoryUnderRoot();
categoryLinkedWithFile = prepareCategoryUnderRoot();
categoryLinkedWithBoth = prepareCategoryUnder(prepareCategoryUnderRoot());
notLinkedCategory = prepareCategoryUnderRoot();
STEP("Link folder and file to categories");
linkContentToCategories(folder, categoryLinkedWithFolder, categoryLinkedWithBoth);
linkContentToCategories(file, categoryLinkedWithFile, categoryLinkedWithBoth);
STEP("Wait for indexing to complete");
Utility.sleep(1000, 60000, () -> restClient.authenticateUser(user)
.withCoreAPI()
.usingCategory(categoryLinkedWithFolder)
.include(INCLUDE_COUNT_PARAM)
.getCategory()
.assertThat()
.field(FIELD_COUNT)
.isNot(0));
}
/**
* Verify count for a category linked with file and folder.
*/
@Test(groups = { TestGroup.REST_API })
public void testGetCategoryById_includeCount()
{
STEP("Get linked category and verify if count is higher than 0");
final RestCategoryModel actualCategory = restClient.authenticateUser(user)
.withCoreAPI()
.usingCategory(categoryLinkedWithBoth)
.include(INCLUDE_COUNT_PARAM)
.getCategory();
restClient.assertStatusCodeIs(OK);
actualCategory.assertThat().field(FIELD_ID).is(categoryLinkedWithBoth.getId());
actualCategory.assertThat().field(FIELD_COUNT).is(2);
}
/**
* Verify count for a category not linked with any content.
*/
@Test(groups = { TestGroup.REST_API })
public void testGetCategoryById_includeCountForNonLinkedCategory()
{
STEP("Get non-linked category and verify if count is 0");
final RestCategoryModel actualCategory = restClient.authenticateUser(user)
.withCoreAPI()
.usingCategory(notLinkedCategory)
.include(INCLUDE_COUNT_PARAM)
.getCategory();
restClient.assertStatusCodeIs(OK);
actualCategory.assertThat().field(FIELD_ID).is(notLinkedCategory.getId());
actualCategory.assertThat().field(FIELD_COUNT).is(0);
}
/**
* Verify count for three categories: linked with file, linked with folder and third not linked to any content.
*/
@Test(groups = { TestGroup.REST_API })
public void testGetCategories_includeCount()
{
STEP("Get few categories and verify its counts");
final RestCategoryModel parentCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
final RestCategoryModelsCollection actualCategories = restClient.authenticateUser(user)
.withCoreAPI()
.usingCategory(parentCategory)
.include(INCLUDE_COUNT_PARAM)
.getCategoryChildren();
restClient.assertStatusCodeIs(OK);
assertTrue(actualCategories.getEntries().stream()
.map(RestCategoryModel::onModel)
.anyMatch(category -> category.getId().equals(categoryLinkedWithFolder.getId()) && category.getCount() == 1));
assertTrue(actualCategories.getEntries().stream()
.map(RestCategoryModel::onModel)
.anyMatch(category -> category.getId().equals(categoryLinkedWithFile.getId()) && category.getCount() == 1));
assertTrue(actualCategories.getEntries().stream()
.map(RestCategoryModel::onModel)
.anyMatch(category -> category.getId().equals(notLinkedCategory.getId()) && category.getCount() == 0));
}
/**
* Create category and verify that its count is 0.
*/
@Test(groups = { TestGroup.REST_API })
public void testCreateCategory_includingCount()
{
STEP("Create a category under root and verify if count is 0");
final String categoryName = getRandomName("Category");
final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
final RestCategoryModel aCategory = createCategoryModelWithName(categoryName);
final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.include(INCLUDE_COUNT_PARAM)
.usingCategory(rootCategory)
.createSingleCategory(aCategory);
STEP("Create a category under root category (as admin)");
restClient.assertStatusCodeIs(CREATED);
createdCategory.assertThat().field(FIELD_NAME).is(categoryName);
createdCategory.assertThat().field(FIELD_COUNT).is(0);
}
/**
* Update category linked to file and folder and verify that its count is 2.
*/
@Test(groups = { TestGroup.REST_API })
public void testUpdateCategory_includeCount()
{
STEP("Update linked category and verify if count is higher than 0");
final String categoryNewName = getRandomName("NewCategoryName");
final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(categoryNewName);
final RestCategoryModel updatedCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(categoryLinkedWithBoth)
.include(INCLUDE_COUNT_PARAM)
.updateCategory(fixedCategoryModel);
restClient.assertStatusCodeIs(OK);
updatedCategory.assertThat().field(FIELD_ID).is(categoryLinkedWithBoth.getId());
updatedCategory.assertThat().field(FIELD_COUNT).is(2);
}
/**
* Update category not linked to any content and verify that its count is 0.
*/
@Test(groups = { TestGroup.REST_API })
public void testUpdateCategory_includeCountForNonLinkedCategory()
{
STEP("Update non-linked category and verify if count is 0");
final String categoryNewName = getRandomName("NewCategoryName");
final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(categoryNewName);
final RestCategoryModel updatedCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(notLinkedCategory)
.include(INCLUDE_COUNT_PARAM)
.updateCategory(fixedCategoryModel);
restClient.assertStatusCodeIs(OK);
updatedCategory.assertThat().field(FIELD_ID).is(notLinkedCategory.getId());
updatedCategory.assertThat().field(FIELD_COUNT).is(0);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -30,19 +30,29 @@ import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.CREATED;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestCategoryLinkBodyModel;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.model.RestCategoryModelsCollection;
import org.alfresco.utility.model.RepoTestModel;
import org.alfresco.utility.model.UserModel;
import org.testng.annotations.BeforeClass;
abstract class CategoriesRestTest extends RestTest
{
protected static final String INCLUDE_COUNT_PARAM = "count";
protected static final String ROOT_CATEGORY_ID = "-root-";
protected static final String CATEGORY_NAME_PREFIX = "CategoryName";
protected static final String FIELD_NAME = "name";
protected static final String FIELD_ID = "id";
protected static final String FIELD_PARENT_ID = "parentId";
protected static final String FIELD_HAS_CHILDREN = "hasChildren";
protected static final String FIELD_COUNT = "count";
protected UserModel user;
@@ -53,14 +63,26 @@ abstract class CategoriesRestTest extends RestTest
user = dataUser.createRandomTestUser();
}
protected RestCategoryModel prepareCategoryUnderRoot()
protected RestCategoryModelsCollection linkContentToCategories(final RepoTestModel node, final RestCategoryModel... categories)
{
return prepareCategoryUnder(ROOT_CATEGORY_ID);
final List<RestCategoryLinkBodyModel> categoryLinkModels = Arrays.stream(categories)
.map(RestCategoryModel::getId)
.map(this::createCategoryLinkModelWithId)
.collect(Collectors.toList());
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(user).withCoreAPI().usingNode(node).linkToCategories(categoryLinkModels);
restClient.assertStatusCodeIs(CREATED);
return linkedCategories;
}
protected RestCategoryModel prepareCategoryUnder(final String parentId)
protected RestCategoryModel prepareCategoryUnderRoot()
{
return prepareCategoryUnder(createCategoryModelWithId(ROOT_CATEGORY_ID));
}
protected RestCategoryModel prepareCategoryUnder(final RestCategoryModel parentCategory)
{
final RestCategoryModel parentCategory = createCategoryModelWithId(parentId);
final RestCategoryModel categoryModel = createCategoryModelWithName(getRandomName(CATEGORY_NAME_PREFIX));
final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
@@ -71,6 +93,30 @@ abstract class CategoriesRestTest extends RestTest
return createdCategory;
}
protected List<RestCategoryModel> prepareCategoriesUnderRoot(final int categoriesCount)
{
return prepareCategoriesUnder(ROOT_CATEGORY_ID, categoriesCount);
}
protected List<RestCategoryModel> prepareCategoriesUnder(final String parentId, final int categoriesCount)
{
final RestCategoryModel parentCategory = createCategoryModelWithId(parentId);
final List<RestCategoryModel> categoryModels = IntStream
.range(0, categoriesCount)
.mapToObj(i -> createCategoryModelWithName(getRandomName(CATEGORY_NAME_PREFIX)))
.collect(Collectors.toList());
final List<RestCategoryModel> createdCategories = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(parentCategory)
.createCategoriesList(categoryModels)
.getEntries().stream()
.map(RestCategoryModel::onModel)
.collect(Collectors.toList());
restClient.assertStatusCodeIs(CREATED);
return createdCategories;
}
protected RestCategoryModel createCategoryModelWithId(final String id)
{
return createCategoryModelWithIdAndName(id, null);
@@ -88,4 +134,18 @@ abstract class CategoriesRestTest extends RestTest
.name(name)
.create();
}
protected RestCategoryLinkBodyModel createCategoryLinkModelWithId(final String id)
{
return RestCategoryLinkBodyModel.builder()
.categoryId(id)
.create();
}
protected RepoTestModel createNodeModelWithId(final String id)
{
final RepoTestModel nodeModel = new RepoTestModel() {};
nodeModel.setNodeRef(id);
return nodeModel;
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -26,6 +26,7 @@
package org.alfresco.rest.categories;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CREATED;
@@ -38,7 +39,6 @@ import java.util.stream.IntStream;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.model.RestCategoryModelsCollection;
import org.alfresco.utility.data.RandomData;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestGroup;
@@ -56,7 +56,7 @@ public class CreateCategoriesTests extends CategoriesRestTest
{
STEP("Create a category under root category (as admin)");
final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
final RestCategoryModel aCategory = createCategoryModelWithName(getRandomName("Category"));
final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(rootCategory)
@@ -92,7 +92,7 @@ public class CreateCategoriesTests extends CategoriesRestTest
{
STEP("Create a category under root category (as admin)");
final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
final RestCategoryModel aCategory = createCategoryModelWithName(getRandomName("Category"));
final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(rootCategory)
@@ -140,7 +140,7 @@ public class CreateCategoriesTests extends CategoriesRestTest
{
STEP("Create a category under root category (as admin)");
final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
final RestCategoryModel aCategory = createCategoryModelWithName(getRandomName("Category"));
final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(rootCategory)
@@ -186,7 +186,7 @@ public class CreateCategoriesTests extends CategoriesRestTest
{
STEP("Create a category under root category (as user)");
final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
final RestCategoryModel aCategory = createCategoryModelWithName(getRandomName("Category"));
restClient.authenticateUser(user)
.withCoreAPI()
.usingCategory(rootCategory)
@@ -203,7 +203,7 @@ public class CreateCategoriesTests extends CategoriesRestTest
STEP("Create a category under non existing category node (as admin)");
final String id = "non-existing-node-id";
final RestCategoryModel rootCategory = createCategoryModelWithId(id);
final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
final RestCategoryModel aCategory = createCategoryModelWithName(getRandomName("Category"));
restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(rootCategory)
@@ -223,7 +223,7 @@ public class CreateCategoriesTests extends CategoriesRestTest
STEP("Create a category under folder node (as admin)");
final RestCategoryModel rootCategory = createCategoryModelWithId(folder.getNodeRef());
final RestCategoryModel aCategory = createCategoryModelWithName(RandomData.getRandomName("Category"));
final RestCategoryModel aCategory = createCategoryModelWithName(getRandomName("Category"));
restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(rootCategory)
@@ -231,10 +231,31 @@ public class CreateCategoriesTests extends CategoriesRestTest
restClient.assertStatusCodeIs(BAD_REQUEST).assertLastError().containsSummary("Node id does not refer to a valid category");
}
/**
* Check weather count present in create category request will be ignored.
*/
@Test(groups = { TestGroup.REST_API })
public void testCreateCategoryUnderRoot_verifyIfCountInRequestIsIgnored()
{
STEP("Try to create a category with filled count under root");
final RestCategoryModel rootCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
final RestCategoryModel aCategory = createCategoryModelWithName(getRandomName("Category"));
aCategory.setCount(2);
final RestCategoryModel createdCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(rootCategory)
.include(INCLUDE_COUNT_PARAM)
.createSingleCategory(aCategory);
restClient.assertStatusCodeIs(CREATED);
createdCategory.assertThat().field(FIELD_NAME).is(aCategory.getName());
createdCategory.assertThat().field(FIELD_COUNT).is(0);
}
static List<RestCategoryModel> getCategoriesToCreate(final int count)
{
return IntStream.range(0, count)
.mapToObj(i -> RestCategoryModel.builder().name(RandomData.getRandomName("SubCategory")).create())
.mapToObj(i -> RestCategoryModel.builder().name(getRandomName("SubCategory")).create())
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,522 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2023 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.categories;
import static org.alfresco.utility.constants.UserRole.SiteManager;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.NO_CONTENT;
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
import javax.json.Json;
import java.util.Collections;
import java.util.List;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.model.RestCategoryLinkBodyModel;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.model.RestCategoryModelsCollection;
import org.alfresco.rest.model.RestNodeModel;
import org.alfresco.rest.model.RestTagModel;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.RepoTestModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.model.UserModel;
import org.apache.commons.lang3.StringUtils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class LinkToCategoriesTests extends CategoriesRestTest
{
private static final String ASPECTS_FIELD = "aspectNames";
private static final String PROPERTIES_FIELD = "properties";
private SiteModel site;
private FolderModel folder;
private FileModel file;
private RestCategoryModel category;
@BeforeClass(alwaysRun = true)
@Override
public void dataPreparation()
{
STEP("Create user and a site");
user = dataUser.createRandomTestUser();
site = dataSite.usingUser(user).createPublicRandomSite();
}
@BeforeMethod(alwaysRun = true)
public void setUp()
{
STEP("Create a folder, file in it and a category under root");
folder = dataContent.usingUser(user).usingSite(site).createFolder();
file = dataContent.usingUser(user).usingResource(folder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
category = prepareCategoryUnderRoot();
}
/**
* Link content to category and verify if this category is present in node's properties
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory()
{
STEP("Check if file is not linked to any category");
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(ASPECTS_FIELD).notContains("cm:generalclassifiable");
fileNode.assertThat().field(PROPERTIES_FIELD).notContains("cm:categories");
STEP("Link content to created category and expect 201");
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(category.getId());
final RestCategoryModel linkedCategory = restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(CREATED);
linkedCategory.assertThat().isEqualTo(category);
STEP("Verify if category is present in file metadata");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(ASPECTS_FIELD).contains("cm:generalclassifiable");
fileNode.assertThat().field(PROPERTIES_FIELD).contains("cm:categories");
fileNode.assertThat().field(PROPERTIES_FIELD).contains(category.getId());
}
/**
* Link content to two categories and verify if both are present in node's properties
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToMultipleCategories()
{
STEP("Check if file is not linked to any category");
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(ASPECTS_FIELD).notContains("cm:generalclassifiable");
fileNode.assertThat().field(PROPERTIES_FIELD).notContains("cm:categories");
STEP("Create second category under root");
final RestCategoryModel secondCategory = prepareCategoryUnderRoot();
STEP("Link content to created categories and expect 201");
final List<RestCategoryLinkBodyModel> categoryLinkModels = List.of(
createCategoryLinkModelWithId(category.getId()),
createCategoryLinkModelWithId(secondCategory.getId())
);
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategories(categoryLinkModels);
restClient.assertStatusCodeIs(CREATED);
linkedCategories.getEntries().get(0).onModel().assertThat().isEqualTo(category);
linkedCategories.getEntries().get(1).onModel().assertThat().isEqualTo(secondCategory);
STEP("Verify if both categories are present in file metadata");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(ASPECTS_FIELD).contains("cm:generalclassifiable");
fileNode.assertThat().field(PROPERTIES_FIELD).contains("cm:categories");
fileNode.assertThat().field(PROPERTIES_FIELD).contains(category.getId());
fileNode.assertThat().field(PROPERTIES_FIELD).contains(secondCategory.getId());
}
/**
* Try to link file to three categories, two of which are the same, and expect two distinct categories in output.
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_withRepeatedCategory()
{
STEP("Check if file is not linked to any category");
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(ASPECTS_FIELD).notContains("cm:generalclassifiable");
fileNode.assertThat().field(PROPERTIES_FIELD).notContains("cm:categories");
STEP("Link content to three (one repeated) categories and expect 201");
final RestCategoryModel secondCategory = prepareCategoryUnderRoot();
final List<RestCategoryLinkBodyModel> categoryLinkModels = List.of(
createCategoryLinkModelWithId(category.getId()),
createCategoryLinkModelWithId(secondCategory.getId()),
createCategoryLinkModelWithId(category.getId())
);
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategories(categoryLinkModels);
restClient.assertStatusCodeIs(CREATED);
linkedCategories.assertThat().entriesListCountIs(2);
linkedCategories.getEntries().get(0).onModel().assertThat().isEqualTo(category);
linkedCategories.getEntries().get(1).onModel().assertThat().isEqualTo(secondCategory);
STEP("Verify if repeated category was ignored and only two categories are present in file metadata");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(PROPERTIES_FIELD).containsOnce(category.getId());
fileNode.assertThat().field(PROPERTIES_FIELD).containsOnce(secondCategory.getId());
}
/**
* Try to link file to already linked category and expect distinct categories in response.
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_usingAlreadyLinkedCategory()
{
STEP("Create second category under root");
final RestCategoryModel secondCategory = prepareCategoryUnderRoot();
STEP("Link file to one category");
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(category.getId());
restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLinkModel);
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(PROPERTIES_FIELD).containsOnce(category.getId());
fileNode.assertThat().field(PROPERTIES_FIELD).notContains(secondCategory.getId());
STEP("Link content to two categories using one already linked before to and expect 201");
final List<RestCategoryLinkBodyModel> categoryLinkModels = List.of(
createCategoryLinkModelWithId(category.getId()),
createCategoryLinkModelWithId(secondCategory.getId())
);
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategories(categoryLinkModels);
restClient.assertStatusCodeIs(CREATED);
linkedCategories.assertThat().entriesListCountIs(2);
linkedCategories.getEntries().get(0).onModel().assertThat().isEqualTo(category);
linkedCategories.getEntries().get(1).onModel().assertThat().isEqualTo(secondCategory);
STEP("Verify if repeated category was ignored and only two categories are present in file metadata");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(PROPERTIES_FIELD).containsOnce(category.getId());
fileNode.assertThat().field(PROPERTIES_FIELD).containsOnce(secondCategory.getId());
}
/**
* Link content, which already has some linked category to new ones and verify if all categories are present in node's properties
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_usingContentWithAlreadyLinkedCategories()
{
STEP("Link content to created category");
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(category.getId());
restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(CREATED);
STEP("Create second and third category under root, link content to them and expect 201");
final RestCategoryModel secondCategory = prepareCategoryUnderRoot();
final RestCategoryModel thirdCategory = prepareCategoryUnderRoot();
final List<RestCategoryLinkBodyModel> categoryLinkModels = List.of(
createCategoryLinkModelWithId(secondCategory.getId()),
createCategoryLinkModelWithId(thirdCategory.getId())
);
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategories(categoryLinkModels);
restClient.assertStatusCodeIs(CREATED);
linkedCategories.assertThat().entriesListCountIs(2);
linkedCategories.getEntries().get(0).onModel().assertThat().isEqualTo(secondCategory);
linkedCategories.getEntries().get(1).onModel().assertThat().isEqualTo(thirdCategory);
STEP("Verify if all three categories are present in file metadata");
final RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(PROPERTIES_FIELD).contains("cm:categories");
fileNode.assertThat().field(PROPERTIES_FIELD).contains(category.getId());
fileNode.assertThat().field(PROPERTIES_FIELD).contains(secondCategory.getId());
fileNode.assertThat().field(PROPERTIES_FIELD).contains(thirdCategory.getId());
}
/**
* Try to link content to category as a user without read permission and expect 403 (Forbidden)
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_asUserWithoutReadPermissionAndExpect403()
{
STEP("Try to link content to a category using user without read permission and expect 403");
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(category.getId());
final UserModel userWithoutRights = dataUser.createRandomTestUser();
restClient.authenticateUser(userWithoutRights).withCoreAPI().usingNode(file).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(FORBIDDEN);
}
/**
* Try to link content to category as a user without change and expect 403 (Forbidden)
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_asUserWithoutChangePermissionAndExpect403()
{
STEP("Create another user as a consumer for file");
final UserModel consumer = dataUser.createRandomTestUser();
allowPermissionsForUser(consumer.getUsername(), "Consumer", file);
STEP("Try to link content to a category using user without change permission and expect 403");
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(category.getId());
restClient.authenticateUser(consumer).withCoreAPI().usingNode(file).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(FORBIDDEN);
}
/**
* Try to link content to category as owner and expect 201
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_asOwner()
{
STEP("Use admin to create a private site");
final SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
STEP("Add the user to the site, let him create a folder and then evict him from the site again");
dataUser.addUserToSite(user, privateSite, SiteManager);
final FolderModel privateFolder = dataContent.usingUser(user).usingSite(privateSite).createFolder();
final FileModel privateFile = dataContent.usingUser(user).usingResource(privateFolder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
dataUser.removeUserFromSite(user, privateSite);
STEP("Try to link content to a category as owner and expect 201");
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(category.getId());
restClient.authenticateUser(user).withCoreAPI().usingNode(privateFile).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(CREATED);
}
/**
* Try to link content to category using non-existing category and expect 404 (Not Found)
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_usingNonExistingCategoryAndExpect404()
{
STEP("Try to link content to non-existing category and expect 404");
final String nonExistingCategoryId = "non-existing-dummy-id";
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(nonExistingCategoryId);
restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(NOT_FOUND);
}
/**
* Try to link content to category passing empty list as input and expect 400 (Bad Request)
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_passingEmptyListAndExpect400()
{
STEP("Try to call link content API with empty list and expect 400");
restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategories(Collections.emptyList());
restClient.assertStatusCodeIs(BAD_REQUEST);
}
/**
* Try to link content to category passing invalid ID in input list and expect 400 (Bad Request)
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_passingEmptyIdAndExpect400()
{
STEP("Try to call link content API with empty category ID and expect 400");
final String nonExistingCategoryId = StringUtils.EMPTY;
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(nonExistingCategoryId);
restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
}
/**
* Link folder node to category and expect 201 (Created)
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkFolderToCategory()
{
STEP("Link folder node to category");
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(category.getId());
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(CREATED);
}
/**
* Try to link non-content node to category and expect 422 (Unprocessable Entity)
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_usingTagInsteadOfContentAndExpect422()
{
STEP("Add tag to file");
final RestTagModel tag = restClient.authenticateUser(user).withCoreAPI().usingNode(file).addTag("someTag");
final RepoTestModel tagNode = createNodeModelWithId(tag.getId());
STEP("Try to link a tag to category and expect 422");
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(category.getId());
restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI().usingNode(tagNode).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(UNPROCESSABLE_ENTITY);
}
/**
* Try to link content to non-category node and expect 400 (Bad Request)
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_usingFolderInsteadOfCategoryAndExpect400()
{
STEP("Try to link content to non-category and expect 400");
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(folder.getNodeRef());
restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
}
/**
* Try to link content to root category and expect 400 (Bad Request)
*/
@Test(groups = { TestGroup.REST_API})
public void testLinkContentToCategory_usingRootCategoryAndExpect400()
{
STEP("Try to link content to root category and expect 400");
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(ROOT_CATEGORY_ID);
restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLinkModel);
restClient.assertStatusCodeIs(BAD_REQUEST);
}
/**
* Try to link and unlink content from a created category
*/
@Test(groups = {TestGroup.REST_API})
public void testUnlinkContentFromCategory()
{
STEP("Link content to created category and expect 201");
final RestCategoryLinkBodyModel categoryLink = createCategoryLinkModelWithId(category.getId());
final RestCategoryModel linkedCategory = restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLink);
restClient.assertStatusCodeIs(CREATED);
linkedCategory.assertThat().isEqualTo(category);
STEP("Verify that category is present in file metadata");
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(ASPECTS_FIELD).contains("cm:generalclassifiable");
fileNode.assertThat().field(PROPERTIES_FIELD).contains("cm:categories");
fileNode.assertThat().field(PROPERTIES_FIELD).contains(category.getId());
STEP("Unlink content from created category and expect 204");
restClient.authenticateUser(user).withCoreAPI().usingNode(file).unlinkFromCategory(category.getId());
restClient.assertStatusCodeIs(NO_CONTENT);
STEP("Verify that category isn't present in file metadata");
fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(ASPECTS_FIELD).notContains("cm:generalclassifiable");
fileNode.assertThat().field(PROPERTIES_FIELD).notContains("cm:categories");
fileNode.assertThat().field(PROPERTIES_FIELD).notContains(category.getId());
}
/**
* Try to link content to multiple categories and try to unlink content from a single category
* Other categories should remain intact and file should keep having "cm:generalclassifiable" aspect
*/
@Test(groups = {TestGroup.REST_API})
public void testUnlinkContentFromCategory_multipleLinkedCategories()
{
STEP("Create second category under root");
final RestCategoryModel secondCategory = prepareCategoryUnderRoot();
STEP("Link content to created categories and expect 201");
final List<RestCategoryLinkBodyModel> categoryLinks = List.of(
createCategoryLinkModelWithId(category.getId()),
createCategoryLinkModelWithId(secondCategory.getId())
);
restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategories(categoryLinks);
restClient.assertStatusCodeIs(CREATED);
STEP("Unlink content from first category and expect 204");
restClient.authenticateUser(user).withCoreAPI().usingNode(file).unlinkFromCategory(category.getId());
restClient.assertStatusCodeIs(NO_CONTENT);
STEP("Verify that second category is still present in file metadata");
RestNodeModel fileNode = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getNode();
fileNode.assertThat().field(ASPECTS_FIELD).contains("cm:generalclassifiable");
fileNode.assertThat().field(PROPERTIES_FIELD).contains("cm:categories");
fileNode.assertThat().field(PROPERTIES_FIELD).notContains(category.getId());
fileNode.assertThat().field(PROPERTIES_FIELD).contains(secondCategory.getId());
}
/**
* Link content to a category as user with permission and try to unlink content using a user without change permissions
*/
@Test(groups = {TestGroup.REST_API})
public void testUnlinkContentFromCategory_asUserWithoutChangePermissionAndGet403()
{
STEP("Link content to created category and expect 201");
final RestCategoryLinkBodyModel categoryLink = createCategoryLinkModelWithId(category.getId());
final RestCategoryModel linkedCategory = restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLink);
restClient.assertStatusCodeIs(CREATED);
linkedCategory.assertThat().isEqualTo(category);
STEP("Create another user as a consumer for file");
final UserModel consumer = dataUser.createRandomTestUser();
allowPermissionsForUser(consumer.getUsername(), "Consumer", file);
STEP("Try to unlink content to a category using user without change permission and expect 403");
restClient.authenticateUser(consumer).withCoreAPI().usingNode(file).unlinkFromCategory(category.getId());
restClient.assertStatusCodeIs(FORBIDDEN);
}
/**
* Try to unlink content from a category that the node isn't assigned to and expect 404
*/
@Test(groups = { TestGroup.REST_API})
public void testUnlinkContentFromCategory_unlinkFromNonLinkedToNodeCategory()
{
STEP("Try to unlink content from a category that the node isn't assigned to");
final RestCategoryModel nonLinkedToNodeCategory = createCategoryModelWithId("non-linked-category-dummy-id");
restClient.authenticateUser(user).withCoreAPI().usingNode(file).unlinkFromCategory(nonLinkedToNodeCategory.getId());
restClient.assertStatusCodeIs(NOT_FOUND);
}
/**
* Try to unlink content from category using non-existing category id and expect 404 (Not Found)
*/
@Test(groups = { TestGroup.REST_API})
public void testUnlinkContentFromCategory_usingNonExistingCategoryAndExpect404()
{
STEP("Try to unlink content from non-existent category and expect 404");
final String nonExistentCategoryId = "non-existent-dummy-id";
restClient.authenticateUser(user).withCoreAPI().usingNode(file).unlinkFromCategory(nonExistentCategoryId);
restClient.assertStatusCodeIs(NOT_FOUND);
}
private void allowPermissionsForUser(final String username, final String role, final FileModel file)
{
final String putPermissionsBody = Json.createObjectBuilder().add("permissions",
Json.createObjectBuilder()
.add("isInheritanceEnabled", true)
.add("locallySet", Json.createObjectBuilder()
.add("authorityId", username)
.add("name", role)
.add("accessStatus", "ALLOWED")))
.build().toString();
restClient.authenticateUser(user).withCoreAPI().usingNode(file).updateNode(putPermissionsBody);
}
}

View File

@@ -0,0 +1,220 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2023 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.categories;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.OK;
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
import javax.json.Json;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.model.RestCategoryLinkBodyModel;
import org.alfresco.rest.model.RestCategoryModel;
import org.alfresco.rest.model.RestCategoryModelsCollection;
import org.alfresco.rest.model.RestTagModel;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.RepoTestModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.model.UserModel;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class ListCategoriesForNodeTests extends CategoriesRestTest
{
private SiteModel site;
private FolderModel folder;
private FileModel file;
private RestCategoryModel category;
@BeforeClass(alwaysRun = true)
@Override
public void dataPreparation()
{
STEP("Create user and a site");
user = dataUser.createRandomTestUser();
site = dataSite.usingUser(user).createPublicRandomSite();
}
@BeforeMethod(alwaysRun = true)
public void setUp()
{
STEP("Create a folder, file in it and a category under root");
folder = dataContent.usingUser(user).usingSite(site).createFolder();
file = dataContent.usingUser(user).usingResource(folder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
category = prepareCategoryUnderRoot();
}
/**
* Get one linked category using file
*/
@Test(groups = { TestGroup.REST_API})
public void testListSingleCategoryForNode_usingFile()
{
STEP("Link file to category");
final RestCategoryLinkBodyModel categoryLink = createCategoryLinkModelWithId(category.getId());
final RestCategoryModel linkedCategory = restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLink);
STEP("Get linked category");
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getLinkedCategories();
restClient.assertStatusCodeIs(OK);
linkedCategories.assertThat().entriesListCountIs(1);
linkedCategories.getEntries().get(0).onModel().assertThat().isEqualTo(linkedCategory);
}
/**
* Get one linked category using folder
*/
@Test(groups = { TestGroup.REST_API})
public void testListSingleCategoryForNode_usingFolder()
{
STEP("Link folder to category");
final RestCategoryLinkBodyModel categoryLink = createCategoryLinkModelWithId(category.getId());
final RestCategoryModel linkedCategory = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).linkToCategory(categoryLink);
STEP("Get linked category");
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(user).withCoreAPI().usingNode(folder).getLinkedCategories();
restClient.assertStatusCodeIs(OK);
linkedCategories.assertThat().entriesListCountIs(1);
linkedCategories.getEntries().get(0).onModel().assertThat().isEqualTo(linkedCategory);
}
/**
* Get multiple linked categories using file
*/
@Test(groups = { TestGroup.REST_API})
public void testListMultipleCategoriesForNode_usingFile()
{
STEP("Create multiple categories under root");
final List<RestCategoryModel> createdCategories = prepareCategoriesUnderRoot(10);
STEP("Link file to created categories");
final List<RestCategoryLinkBodyModel> categoryLinkModels = createdCategories.stream()
.map(RestCategoryModel::getId)
.map(this::createCategoryLinkModelWithId)
.collect(Collectors.toList());
final List<RestCategoryModel> createdCategoryLinks = restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategories(
categoryLinkModels
).getEntries();
STEP("Get categories which are linked from file and compare them to created category links");
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getLinkedCategories();
restClient.assertStatusCodeIs(OK);
linkedCategories.assertThat().entriesListCountIs(createdCategoryLinks.size());
IntStream.range(0, createdCategoryLinks.size()).forEach(i ->
linkedCategories.getEntries().get(i).onModel().assertThat().isEqualTo(createdCategoryLinks.get(i).onModel())
);
}
/**
* Try to get linked categories for content which is not linked to any category
*/
@Test(groups = { TestGroup.REST_API})
public void testListCategoriesForNode_withoutLinkedCategories()
{
STEP("Try to get linked categories and expect empty list");
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(user).withCoreAPI().usingNode(file).getLinkedCategories();
restClient.assertStatusCodeIs(OK);
linkedCategories.assertThat().entriesListIsEmpty();
}
/**
* Try to get linked categories using non-existing node and expect 404 (Not Found)
*/
@Test(groups = { TestGroup.REST_API})
public void testListCategoriesForNode_usingNonExistingNodeAndExpect404()
{
STEP("Try to get linked categories for non-existing node and expect 404");
final RepoTestModel nonExistingNode = createNodeModelWithId("non-existing-id");
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(user).withCoreAPI().usingNode(nonExistingNode).getLinkedCategories();
restClient.assertStatusCodeIs(NOT_FOUND);
linkedCategories.assertThat().entriesListIsEmpty();
}
/**
* Try to get multiple linked categories as user without read permission and expect 403 (Forbidden)
*/
@Test(groups = { TestGroup.REST_API})
public void testListCategoriesForNode_asUserWithoutReadPermissionAndExpect403()
{
STEP("Link content to category");
final RestCategoryLinkBodyModel categoryLink = createCategoryLinkModelWithId(category.getId());
restClient.authenticateUser(user).withCoreAPI().usingNode(file).linkToCategory(categoryLink);
STEP("Create another user and deny consumer rights");
final UserModel userWithoutRights = dataUser.createRandomTestUser();
denyPermissionsForUser(userWithoutRights.getUsername(), "Consumer", file);
STEP("Try to get linked categories using user without read permission and expect 403");
restClient.authenticateUser(userWithoutRights).withCoreAPI().usingNode(file).getLinkedCategories();
restClient.assertStatusCodeIs(FORBIDDEN);
}
/**
* Try to get linked categories using tag instead of a content and expect 422 (Unprocessable Entity)
*/
@Test(groups = { TestGroup.REST_API})
public void testListCategoriesForNode_usingTagInsteadOfContentAndExpect422()
{
STEP("Add tag to file");
final RestTagModel tag = restClient.authenticateUser(user).withCoreAPI().usingNode(file).addTag("someTag");
final RepoTestModel tagNode = createNodeModelWithId(tag.getId());
STEP("Try to get linked categories for a tag and expect 422");
restClient.authenticateUser(user).withCoreAPI().usingNode(tagNode).getLinkedCategories();
restClient.assertStatusCodeIs(UNPROCESSABLE_ENTITY);
}
private void denyPermissionsForUser(final String username, final String role, final FileModel file)
{
final String putPermissionsBody = Json.createObjectBuilder().add("permissions",
Json.createObjectBuilder()
.add("isInheritanceEnabled", true)
.add("locallySet", Json.createObjectBuilder()
.add("authorityId", username)
.add("name", role)
.add("accessStatus", "DENIED")))
.build().toString();
restClient.authenticateUser(user).withCoreAPI().usingNode(file).updateNode(putPermissionsBody);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -29,6 +29,7 @@ package org.alfresco.rest.categories;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CONFLICT;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.OK;
@@ -78,7 +79,7 @@ public class UpdateCategoriesTests extends CategoriesRestTest
final RestCategoryModel createdCategory = prepareCategoryUnderRoot();
STEP("Prepare as admin a subcategory of root's child category");
final RestCategoryModel createdSubcategory = prepareCategoryUnder(createdCategory.getId());
final RestCategoryModel createdSubcategory = prepareCategoryUnder(createdCategory);
STEP("Update as admin newly created subcategory");
final String categoryNewName = getRandomName(CATEGORY_NEW_NAME_PREFIX);
@@ -93,6 +94,27 @@ public class UpdateCategoriesTests extends CategoriesRestTest
updatedCategory.assertThat().field(FIELD_NAME).is(categoryNewName);
}
/**
* Try to update a category with a name, which is already present within the parent category
*/
@Test(groups = { TestGroup.REST_API})
public void testUpdateCategory_usingRecurringName()
{
STEP("Prepare as admin two categories under root category");
final RestCategoryModel createdCategory = prepareCategoryUnderRoot();
final RestCategoryModel secondCreatedCategory = prepareCategoryUnderRoot();
STEP("Try to update as admin newly created category using name of already present, different category");
final String categoryNewName = secondCreatedCategory.getName();
final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(categoryNewName);
restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(createdCategory)
.updateCategory(fixedCategoryModel);
restClient.assertStatusCodeIs(CONFLICT);
}
/**
* Try to update a category as a user and expect 403 (Forbidden) in response
*/
@@ -211,4 +233,27 @@ public class UpdateCategoriesTests extends CategoriesRestTest
restClient.assertStatusCodeIs(OK);
updatedCategory.assertThat().field(FIELD_NAME).is(categoryNewName);
}
/**
* Check whether count present in update category request will be ignored.
*/
@Test(groups = { TestGroup.REST_API })
public void testUpdateCategory_verifyIfCountInRequestIsIgnored()
{
STEP("Prepare a category under root category");
final RestCategoryModel createdCategory = prepareCategoryUnderRoot();
STEP("Try to update newly created category providing new name and count number");
final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(getRandomName(CATEGORY_NEW_NAME_PREFIX));
fixedCategoryModel.setCount(2);
final RestCategoryModel updatedCategory = restClient.authenticateUser(dataUser.getAdminUser())
.withCoreAPI()
.usingCategory(createdCategory)
.include(INCLUDE_COUNT_PARAM)
.updateCategory(fixedCategoryModel);
restClient.assertStatusCodeIs(OK);
updatedCategory.assertThat().field(FIELD_ID).is(createdCategory.getId());
updatedCategory.assertThat().field(FIELD_COUNT).is(0);
}
}

View File

@@ -14,7 +14,6 @@ import org.alfresco.utility.testrail.annotation.TestRail;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Ignore;
import org.testng.annotations.Test;
public class AddFavoritesTests extends RestTest
@@ -355,7 +354,6 @@ public class AddFavoritesTests extends RestTest
@TestRail(section = { TestGroup.REST_API, TestGroup.FAVORITES }, executionType = ExecutionType.REGRESSION,
description = "Verify add file favorite with tag id returns status code 404")
@Test(groups = { TestGroup.REST_API, TestGroup.FAVORITES, TestGroup.REGRESSION })
@Ignore
public void addFileFavoriteUsingTagId() throws Exception
{
FileModel file = dataContent.usingSite(siteModel).usingUser(adminUserModel).createContent(CMISUtil.DocumentType.TEXT_PLAIN);

View File

@@ -44,20 +44,20 @@ public abstract class RenditionIntegrationTests extends RestTest
// 2. Create a rendition of the file using RESTAPI
restClient.withCoreAPI().usingNode(file).createNodeRendition(renditionId);
Assert.assertEquals(Integer.valueOf(restClient.getStatusCode()).intValue(), HttpStatus.ACCEPTED.value(),
"Failed to submit a request for rendition. [" + fileName+ ", " + renditionId+"] [source file, rendition ID]. ");
"Failed to submit a request for rendition. [" + fileName + ", " + nodeId + ", " + renditionId + "] [source file, node ID, rendition ID]");
// 3. Verify that a rendition of the file is created and has content using RESTAPI
RestResponse restResponse = restClient.withCoreAPI().usingNode(file).getNodeRenditionContentUntilIsCreated(renditionId);
Assert.assertEquals(Integer.valueOf(restClient.getStatusCode()).intValue(), HttpStatus.OK.value(),
"Failed to produce rendition. [" + fileName+ ", " + renditionId+"] [source file, rendition ID] ");
"Failed to produce rendition. [" + fileName + ", " + nodeId + ", " + renditionId + "] [source file, node ID, rendition ID]");
// 4. Check the returned content type
Assert.assertEquals(restClient.getResponseHeaders().getValue("Content-Type"), expectedMimeType+";charset=UTF-8",
"Rendition was created but it has the wrong Content-Type. [" + fileName+ ", " + renditionId + "] [source file, rendition ID]");
"Rendition was created but it has the wrong Content-Type. [" + fileName+ ", " + nodeId + ", " + renditionId + "] [source file, node ID, rendition ID]");
Assert.assertTrue((restResponse.getResponse().body().asInputStream().available() > 0),
"Rendition was created but its content is empty. [" + fileName+ ", " + renditionId+"] [source file, rendition ID] ");
"Rendition was created but its content is empty. [" + fileName + ", " + nodeId + ", " + renditionId + "] [source file, node ID, rendition ID]");
}
/**

View File

@@ -0,0 +1,226 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2023 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.tags;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
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.OK;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestTagModel;
import org.alfresco.rest.model.RestTagModelsCollection;
import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.model.UserModel;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class CreateTagsTests extends RestTest
{
private static final String FIELD_ID = "id";
private static final String FIELD_TAG = "tag";
private static final String FIELD_COUNT = "count";
private static final String TAG_NAME_PREFIX = "tag-name";
private UserModel admin;
private UserModel user;
@BeforeClass
public void init()
{
admin = dataUser.getAdminUser();
user = dataUser.createRandomTestUser();
}
/**
* Verify if tag does not exist in the system, create one as admin and check if now it's there.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS })
public void testCreateSingleTag()
{
STEP("Create single tag as admin");
final RestTagModel tagModel = createTagModelWithName(getRandomName("99gat").toLowerCase());
final RestTagModel createdTag = restClient.authenticateUser(admin).withCoreAPI().createSingleTag(tagModel);
restClient.assertStatusCodeIs(CREATED);
createdTag.assertThat().field(FIELD_TAG).is(tagModel.getTag())
.assertThat().field(FIELD_ID).isNotEmpty();
STEP("Verify that tag does exist in the system");
RestTagModel tag = restClient.authenticateUser(admin).withCoreAPI().getTag(createdTag);
restClient.assertStatusCodeIs(OK);
tag.assertThat().isEqualTo(createdTag);
}
/**
* Create multiple orphan tags.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS })
public void testCreateMultipleTags()
{
STEP("Create several tags as admin");
final List<RestTagModel> tagModels = IntStream.range(0, 3)
.mapToObj(i -> createTagModelWithName(getRandomName(TAG_NAME_PREFIX + "-" + i).toLowerCase()))
.collect(Collectors.toList());
final RestTagModelsCollection createdTags = restClient.authenticateUser(admin).withCoreAPI().createTags(tagModels);
restClient.assertStatusCodeIs(CREATED);
IntStream.range(0, tagModels.size())
.forEach(i -> createdTags.getEntries().get(i).onModel()
.assertThat().field(FIELD_TAG).is(tagModels.get(i).getTag())
.assertThat().field(FIELD_ID).isNotEmpty()
);
}
/**
* Verify that tag name's case will be lowered.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS })
public void testCreateSingleTag_usingUppercaseName()
{
STEP("Create single tag as admin using uppercase name");
final RestTagModel tagModel = createTagModelWithName(getRandomName(TAG_NAME_PREFIX).toUpperCase());
final RestTagModel createdTag = restClient.authenticateUser(admin).withCoreAPI().createSingleTag(tagModel);
restClient.assertStatusCodeIs(CREATED);
createdTag.assertThat().field(FIELD_TAG).is(tagModel.getTag().toLowerCase())
.assertThat().field(FIELD_ID).isNotEmpty();
}
/**
* Try to create few tags including repeating ones. Repeated tags should be omitted.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS })
public void testCreateMultipleTags_withRepeatedName()
{
STEP("Create models of tags");
final String repeatedTagName = getRandomName(TAG_NAME_PREFIX).toLowerCase();
final List<RestTagModel> tagModels = List.of(
createTagModelWithName(repeatedTagName),
createTagModelWithName(getRandomName(TAG_NAME_PREFIX).toLowerCase()),
createTagModelWithName(repeatedTagName)
);
STEP("Create several tags skipping repeating names");
final RestTagModelsCollection createdTags = restClient.authenticateUser(admin).withCoreAPI().createTags(tagModels);
restClient.assertStatusCodeIs(CREATED);
createdTags.assertThat().entriesListCountIs(2);
createdTags.assertThat().entriesListContains(FIELD_TAG, tagModels.get(0).getTag())
.and().entriesListContains(FIELD_TAG, tagModels.get(1).getTag());
}
/**
* Try to create a tag as a common user and expect 403 (Forbidden)
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS })
public void testCreateTag_asUser()
{
STEP("Try to create single tag as a common user and expect 403");
final RestTagModel tagModel = createTagModelWithRandomName();
restClient.authenticateUser(user).withCoreAPI().createSingleTag(tagModel);
restClient.assertStatusCodeIs(FORBIDDEN);
}
/**
* Try to call create tag API passing empty list and expect 400 (Bad Request)
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS })
public void testCreateTags_passingEmptyList()
{
STEP("Pass empty list while creating tags and expect 400");
restClient.authenticateUser(admin).withCoreAPI().createTags(Collections.emptyList());
restClient.assertStatusCodeIs(BAD_REQUEST);
}
/**
* Try to create a tag, which already exists in the system and expect 409 (Conflict)
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS })
public void testCreateTag_usingAlreadyExistingTagName()
{
STEP("Create some tag in the system");
final RestTagModel tagToCreate = createTagModelWithRandomName();
final RestTagModel alreadyExistingTag = prepareOrphanTag(tagToCreate);
// set original name instead the case lowered one
alreadyExistingTag.setTag(tagToCreate.getTag());
STEP("Try to use already existing tag to create duplicate and expect 409");
restClient.authenticateUser(admin).withCoreAPI().createSingleTag(alreadyExistingTag);
restClient
.assertStatusCodeIs(CONFLICT)
.assertLastError().containsSummary("Duplicate child name not allowed: " + alreadyExistingTag.getTag().toLowerCase());
}
/**
* Verify if count field is 0 for newly created tags.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS })
public void testCreateTag_includingCount()
{
STEP("Create single tag as admin including count and verify if it is 0");
final RestTagModel tagModel = createTagModelWithName(getRandomName(TAG_NAME_PREFIX).toLowerCase());
final RestTagModel createdTag = restClient.authenticateUser(admin).withCoreAPI().include(FIELD_COUNT).createSingleTag(tagModel);
restClient.assertStatusCodeIs(CREATED);
createdTag.assertThat().field(FIELD_TAG).is(tagModel.getTag())
.assertThat().field(FIELD_ID).isNotEmpty()
.assertThat().field(FIELD_COUNT).is(0);
}
private RestTagModel prepareOrphanTagWithRandomName()
{
return prepareOrphanTag(createTagModelWithRandomName());
}
private RestTagModel prepareOrphanTag(final RestTagModel tagModel)
{
final RestTagModel tag = restClient.authenticateUser(admin).withCoreAPI().createSingleTag(tagModel);
restClient.assertStatusCodeIs(CREATED);
return tag;
}
private static RestTagModel createTagModelWithRandomName()
{
return createTagModelWithName(getRandomName(TAG_NAME_PREFIX));
}
private static RestTagModel createTagModelWithName(final String tagName)
{
return RestTagModel.builder().tag(tagName).create();
}
}

View File

@@ -0,0 +1,88 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2023 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.tags;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.model.RestTagModel;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.model.TestGroup;
import org.testng.annotations.Test;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.FORBIDDEN;
import static org.springframework.http.HttpStatus.NOT_FOUND;
import static org.springframework.http.HttpStatus.NO_CONTENT;
public class DeleteTagsTests extends TagsDataPrep
{
/**
* Check we can delete a tag by its id.
*/
@Test(groups = {TestGroup.REST_API})
public void testDeleteTag()
{
STEP("Create a tag assigned to a document and send a request to delete it.");
document = dataContent.usingUser(adminUserModel).usingSite(siteModel).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
RestTagModel aTag = createTagForDocument(document);
restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI().usingTag(aTag).deleteTag();
restClient.assertStatusCodeIs(NO_CONTENT);
STEP("Ensure that the tag has been deleted by sending a GET request and receiving 404.");
restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI().getTag(aTag);
restClient.assertStatusCodeIs(NOT_FOUND);
}
/**
* Attempt to delete a tag as a site manager and receive 403 error.
* Other user roles have fewer permissions than a SiteManager and thus would also be forbidden from deleting a tag.
*/
@Test(groups = {TestGroup.REST_API})
public void testDeleteTagAsSiteManager_andFail()
{
STEP("Create a tag assigned to a document and attempt to delete as a site manager");
document = dataContent.usingUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager)).usingSite(siteModel).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
RestTagModel aTag = createTagForDocument(document);
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager)).withCoreAPI().usingTag(aTag).deleteTag();
restClient.assertStatusCodeIs(FORBIDDEN).assertLastError().containsSummary("Current user does not have permission to manage a tag");
}
/**
* Check we receive 404 error when trying to delete a tag with a non-existent id
*/
@Test(groups = {TestGroup.REST_API})
public void testDeleteNonExistentTag()
{
STEP("Attempt to delete tag with non-existent id and receive 404 error");
final String id = "non-existing-dummy-id";
final RestTagModel tagModel = createTagModelWithId(id);
restClient.authenticateUser(dataUser.getAdminUser()).withCoreAPI().usingTag(tagModel).deleteTag();
restClient.assertStatusCodeIs(NOT_FOUND);
}
}

View File

@@ -1,5 +1,10 @@
package org.alfresco.rest.tags;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.OK;
import org.alfresco.rest.model.RestErrorModel;
import org.alfresco.rest.model.RestTagModel;
import org.alfresco.utility.constants.UserRole;
@@ -14,6 +19,11 @@ import org.testng.annotations.Test;
public class GetTagTests extends TagsDataPrep
{
private static final String FIELD_ID = "id";
private static final String FIELD_TAG = "tag";
private static final String FIELD_COUNT = "count";
private static final String TAG_NAME_PREFIX = "tag-name";
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION, description = "Verify admin user gets tag using REST API and status code is OK (200)")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void adminIsAbleToGetTag() throws Exception
@@ -128,4 +138,25 @@ public class GetTagTests extends TagsDataPrep
.descriptionURLIs(RestErrorModel.RESTAPIEXPLORER)
.stackTraceIs(RestErrorModel.STACKTRACE);
}
}
/**
* Verify that count field is not present for searched tag.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION})
public void testGetTag_notIncludingCount()
{
STEP("Create single tag as admin");
final RestTagModel tagModel = createTagModelWithName(getRandomName(TAG_NAME_PREFIX).toLowerCase());
final RestTagModel createdTag = restClient.authenticateUser(adminUserModel).withCoreAPI().createSingleTag(tagModel);
restClient.assertStatusCodeIs(CREATED);
STEP("Get a single tag, not including count and verify if it is not present in the response");
final RestTagModel searchedTag = restClient.withCoreAPI().getTag(createdTag);
restClient.assertStatusCodeIs(OK);
searchedTag.assertThat().field(FIELD_TAG).is(tagModel.getTag())
.assertThat().field(FIELD_ID).isNotEmpty()
.assertThat().field(FIELD_COUNT).isNull();
}
}

View File

@@ -1,34 +1,36 @@
package org.alfresco.rest.tags;
import static org.alfresco.utility.data.RandomData.getRandomName;
import static org.alfresco.utility.report.log.Step.STEP;
import static org.springframework.http.HttpStatus.OK;
import java.util.Set;
import org.alfresco.rest.model.RestErrorModel;
import org.alfresco.rest.model.RestTagModel;
import org.alfresco.rest.model.RestTagModelsCollection;
import org.alfresco.utility.constants.UserRole;
import org.alfresco.utility.data.RandomData;
import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.testrail.ExecutionType;
import org.alfresco.utility.testrail.annotation.TestRail;
import org.springframework.http.HttpStatus;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@Test(groups = {TestGroup.REQUIRE_SOLR})
public class GetTagsTests extends TagsDataPrep
{
@BeforeClass(alwaysRun = true)
public void dataPreparation() throws Exception
{
init();
}
private static final String FIELD_ID = "id";
private static final String FIELD_TAG = "tag";
private static final String FIELD_COUNT = "count";
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.SANITY, description = "Verify user with Manager role gets tags using REST API and status code is OK (200)")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.SANITY })
public void getTagsWithManagerRole() throws Exception
public void getTagsWithManagerRole()
{
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager));
returnedCollection = restClient.withParams("maxItems=10000").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
returnedCollection.assertThat().entriesListIsNotEmpty()
.and().entriesListContains("tag", documentTagValue.toLowerCase())
.and().entriesListContains("tag", documentTagValue2.toLowerCase());
@@ -36,11 +38,11 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION, description = "Verify user with Collaborator role gets tags using REST API and status code is OK (200)")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void getTagsWithCollaboratorRole() throws Exception
public void getTagsWithCollaboratorRole()
{
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteCollaborator));
returnedCollection = restClient.withParams("maxItems=10000").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
returnedCollection.assertThat().entriesListIsNotEmpty()
.and().entriesListContains("tag", documentTagValue.toLowerCase())
.and().entriesListContains("tag", documentTagValue2.toLowerCase());
@@ -48,11 +50,11 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION, description = "Verify user with Contributor role gets tags using REST API and status code is OK (200)")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void getTagsWithContributorRole() throws Exception
public void getTagsWithContributorRole()
{
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteContributor));
returnedCollection = restClient.withParams("maxItems=10000").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
returnedCollection.assertThat().entriesListIsNotEmpty()
.and().entriesListContains("tag", documentTagValue.toLowerCase())
.and().entriesListContains("tag", documentTagValue2.toLowerCase());
@@ -60,11 +62,11 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION, description = "Verify user with Consumer role gets tags using REST API and status code is OK (200)")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void getTagsWithConsumerRole() throws Exception
public void getTagsWithConsumerRole()
{
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteConsumer));
returnedCollection = restClient.withParams("maxItems=10000").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
returnedCollection.assertThat().entriesListIsNotEmpty()
.and().entriesListContains("tag", documentTagValue.toLowerCase())
.and().entriesListContains("tag", documentTagValue2.toLowerCase());
@@ -73,7 +75,7 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.SANITY, description = "Failed authentication get tags call returns status code 401 with Manager role")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.SANITY })
// @Bug(id="MNT-16904", description = "It fails only on environment with tenants")
public void failedAuthenticationReturnsUnauthorizedStatus() throws Exception
public void failedAuthenticationReturnsUnauthorizedStatus()
{
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager));
userModel = dataUser.createRandomTestUser();
@@ -87,7 +89,7 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "Verify that if maxItems is invalid status code returned is 400")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION})
public void maxItemsInvalidValueTest() throws Exception
public void maxItemsInvalidValueTest()
{
restClient.authenticateUser(adminUserModel).withParams("maxItems=abc").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError().containsSummary(String.format(RestErrorModel.INVALID_MAXITEMS, "abc"));
@@ -96,7 +98,7 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "Verify that if skipCount is invalid status code returned is 400")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION})
public void skipCountInvalidValueTest() throws Exception
public void skipCountInvalidValueTest()
{
restClient.authenticateUser(adminUserModel).withParams("skipCount=abc").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST).assertLastError().containsSummary(String.format(RestErrorModel.INVALID_SKIPCOUNT, "abc"));
@@ -105,11 +107,11 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "Verify that file tag is retrieved")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION})
public void fileTagIsRetrieved() throws Exception
public void fileTagIsRetrieved()
{
restClient.authenticateUser(adminUserModel);
returnedCollection = restClient.withParams("maxItems=10000").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
returnedCollection.assertThat().entriesListIsNotEmpty()
.and().entriesListContains("tag", documentTagValue.toLowerCase())
.and().entriesListContains("tag", documentTagValue2.toLowerCase());
@@ -118,11 +120,11 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "Verify that folder tag is retrieved")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION})
public void folderTagIsRetrieved() throws Exception
public void folderTagIsRetrieved()
{
restClient.authenticateUser(adminUserModel);
returnedCollection = restClient.withParams("maxItems=10000").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
returnedCollection.assertThat().entriesListIsNotEmpty()
.and().entriesListContains("tag", folderTagValue.toLowerCase());
}
@@ -131,11 +133,11 @@ public class GetTagsTests extends TagsDataPrep
description = "Verify site Manager is able to get tags using properties parameter."
+ "Check that properties filter is applied.")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void siteManagerIsAbleToRetrieveTagsWithPropertiesParameter() throws Exception
public void siteManagerIsAbleToRetrieveTagsWithPropertiesParameter()
{
returnedCollection = restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager))
.withParams("maxItems=5000&properties=tag").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
returnedCollection.assertThat().entriesListIsNotEmpty()
.and().entriesListContains("tag", documentTagValue.toLowerCase())
.and().entriesListContains("tag", documentTagValue2.toLowerCase())
@@ -145,15 +147,15 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "With admin get tags and use skipCount parameter. Check pagination")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void useSkipCountCheckPagination() throws Exception
public void useSkipCountCheckPagination()
{
returnedCollection = restClient.authenticateUser(adminUserModel).withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
RestTagModel firstTag = returnedCollection.getEntries().get(0).onModel();
RestTagModel secondTag = returnedCollection.getEntries().get(1).onModel();
RestTagModelsCollection tagsWithSkipCount = restClient.withParams("skipCount=2").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
tagsWithSkipCount.assertThat().entriesListDoesNotContain("tag", firstTag.getTag())
.assertThat().entriesListDoesNotContain("tag", secondTag.getTag());
@@ -163,15 +165,15 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "With admin get tags and use maxItems parameter. Check pagination")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void useMaxItemsParameterCheckPagination() throws Exception
public void useMaxItemsParameterCheckPagination()
{
returnedCollection = restClient.authenticateUser(adminUserModel).withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
RestTagModel firstTag = returnedCollection.getEntries().get(0).onModel();
RestTagModel secondTag = returnedCollection.getEntries().get(1).onModel();
RestTagModelsCollection tagsWithMaxItems = restClient.withParams("maxItems=2").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
tagsWithMaxItems.assertThat().entriesListContains("tag", firstTag.getTag())
.assertThat().entriesListContains("tag", secondTag.getTag())
@@ -182,23 +184,23 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "With manager get tags and use high skipCount parameter. Check pagination")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void useHighSkipCountCheckPagination() throws Exception
public void useHighSkipCountCheckPagination()
{
returnedCollection = restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager))
.withParams("skipCount=20000").withCoreAPI().getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
restClient.assertStatusCodeIs(OK);
returnedCollection.assertThat().entriesListIsEmpty()
.getPagination().assertThat().field("maxItems").is(100)
.and().field("hasMoreItems").is("false")
.and().field("count").is("0")
.and().field("skipCount").is(20000)
.and().field("totalItems").isNull();
.and().field("totalItems").is(0);
}
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "With Collaborator user get tags and use maxItems with value zero. Check default error model schema")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void useMaxItemsWithValueZeroCheckDefaultErrorModelSchema() throws Exception
public void useMaxItemsWithValueZeroCheckDefaultErrorModelSchema()
{
returnedCollection = restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteCollaborator))
.withParams("maxItems=0").withCoreAPI().getTags();
@@ -212,18 +214,167 @@ public class GetTagsTests extends TagsDataPrep
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "With Manager user delete tag. Check it is not retrieved anymore.")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void checkThatDeletedTagIsNotRetrievedAnymore() throws Exception
public void checkThatDeletedTagIsNotRetrievedAnymore()
{
String removedTag = RandomData.getRandomName("tag3");
String removedTag = getRandomName("tag3");
RestTagModel deletedTag = restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager))
.withCoreAPI().usingResource(document).addTag(removedTag);
restClient.withCoreAPI().usingResource(document).deleteTag(deletedTag);
restClient.authenticateUser(adminUserModel).withCoreAPI().usingTag(deletedTag).deleteTag();
restClient.assertStatusCodeIs(HttpStatus.NO_CONTENT);
returnedCollection = restClient.withParams("maxItems=10000").withCoreAPI().getTags();
returnedCollection.assertThat().entriesListIsNotEmpty()
.and().entriesListDoesNotContain("tag", removedTag.toLowerCase());
}
/**
* Verify if exact name filter can be applied.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void testGetTags_withSingleNameFilter()
{
STEP("Get tags with names filter using EQUALS and expect one item in result");
returnedCollection = restClient.authenticateUser(adminUserModel)
.withParams("where=(tag='" + documentTag.getTag() + "')")
.withCoreAPI()
.getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedCollection.assertThat()
.entrySetMatches("tag", Set.of(documentTagValue.toLowerCase()));
}
/**
* Verify if multiple names can be applied as a filter.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void testGetTags_withTwoNameFilters()
{
STEP("Get tags with names filter using IN and expect two items in result");
returnedCollection = restClient.authenticateUser(adminUserModel)
.withParams("where=(tag IN ('" + documentTag.getTag() + "', '" + folderTag.getTag() + "'))")
.withCoreAPI()
.getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedCollection.assertThat()
.entrySetMatches("tag", Set.of(documentTagValue.toLowerCase(), folderTagValue.toLowerCase()));
}
/**
* Verify if alike name filter can be applied.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void testGetTags_whichNamesStartsWithOrphan()
{
STEP("Get tags with names filter using MATCHES and expect one item in result");
returnedCollection = restClient.authenticateUser(adminUserModel)
.withParams("where=(tag MATCHES ('orphan*'))")
.withCoreAPI()
.getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedCollection.assertThat()
.entrySetContains("tag", orphanTag.getTag().toLowerCase());
}
/**
* Verify that tags can be filtered by exact name and alike name at the same time.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void testGetTags_withExactNameAndAlikeFilters()
{
STEP("Get tags with names filter using EQUALS and MATCHES and expect four items in result");
returnedCollection = restClient.authenticateUser(adminUserModel)
.withParams("where=(tag='" + orphanTag.getTag() + "' OR tag MATCHES ('*tag*'))")
.withCoreAPI()
.getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedCollection.assertThat()
.entrySetContains("tag", documentTagValue.toLowerCase(), documentTagValue2.toLowerCase(), folderTagValue.toLowerCase(), orphanTag.getTag().toLowerCase());
}
/**
* Verify if multiple alike filters can be applied.
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void testGetTags_withTwoAlikeFilters()
{
STEP("Get tags applying names filter using MATCHES twice and expect four items in result");
returnedCollection = restClient.authenticateUser(adminUserModel)
.withParams("where=(tag MATCHES ('orphan*') OR tag MATCHES ('tag*'))")
.withCoreAPI()
.getTags();
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedCollection.assertThat()
.entrySetContains("tag", documentTagValue.toLowerCase(), documentTagValue2.toLowerCase(), folderTagValue.toLowerCase(), orphanTag.getTag().toLowerCase());
}
/**
* Verify that providing incorrect field name in where query will result with 400 (Bad Request).
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void testGetTags_withWrongWherePropertyNameAndExpect400()
{
STEP("Try to get tags with names filter using EQUALS and wrong property name and expect 400");
returnedCollection = restClient.authenticateUser(adminUserModel)
.withParams("where=(name=gat)")
.withCoreAPI()
.getTags();
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST)
.assertLastError().containsSummary("Where query error: property with name: name is not expected");
}
/**
* Verify tht AND operator is not supported in where query and expect 400 (Bad Request).
*/
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
public void testGetTags_queryAndOperatorNotSupported()
{
STEP("Try to get tags applying names filter using AND operator and expect 400");
returnedCollection = restClient.authenticateUser(adminUserModel)
.withParams("where=(name=tag AND name IN ('tag-', 'gat'))")
.withCoreAPI()
.getTags();
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST)
.assertLastError().containsSummary("An invalid WHERE query was received. Unsupported Predicate");
}
/**
* Verify if count field is present for searched tags.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION})
public void testGetTags_includingCount()
{
STEP("Get tags including count and verify if it is present in the response");
final RestTagModelsCollection searchedTags = restClient.withCoreAPI().include(FIELD_COUNT).getTags();
restClient.assertStatusCodeIs(OK);
searchedTags.assertThat().entriesListIsNotEmpty()
.assertThat().entriesListContains(FIELD_COUNT)
.assertThat().entriesListContains(FIELD_TAG)
.assertThat().entriesListContains(FIELD_ID);
}
/**
* Verify if count field is not present for searched tags.
*/
@Test(groups = {TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION})
public void testGetTags_notIncludingCount()
{
STEP("Get tags, not including count and verify if it is not in the response");
final RestTagModelsCollection searchedTags = restClient.withCoreAPI().getTags();
restClient.assertStatusCodeIs(OK);
searchedTags.assertThat().entriesListIsNotEmpty()
.assertThat().entriesListDoesNotContain(FIELD_COUNT)
.assertThat().entriesListContains(FIELD_TAG)
.assertThat().entriesListContains(FIELD_ID);
}
}

View File

@@ -1,6 +1,5 @@
package org.alfresco.rest.tags;
import java.util.Date;
import org.alfresco.dataprep.CMISUtil;
import org.alfresco.rest.RestTest;
import org.alfresco.rest.model.RestTagModel;
@@ -12,12 +11,9 @@ import org.alfresco.utility.data.RandomData;
import org.alfresco.utility.model.FileModel;
import org.alfresco.utility.model.FolderModel;
import org.alfresco.utility.model.SiteModel;
import org.alfresco.utility.model.TestGroup;
import org.alfresco.utility.model.UserModel;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
@Test(groups = {TestGroup.REQUIRE_SOLR})
public class TagsDataPrep extends RestTest
{
@@ -28,13 +24,15 @@ public class TagsDataPrep extends RestTest
protected static FileModel document;
protected static FolderModel folder;
protected static String documentTagValue, documentTagValue2, folderTagValue;
protected static RestTagModel documentTag, documentTag2, folderTag, returnedModel;
protected static RestTagModel documentTag, documentTag2, folderTag, orphanTag, returnedModel;
protected static RestTagModelsCollection returnedCollection;
@BeforeClass
public void init() throws Exception
{
//Create users
adminUserModel = dataUser.getAdminUser();
userModel = dataUser.createRandomTestUser();
//Create public site
siteModel = dataSite.usingUser(adminUserModel).createPublicRandomSite();
usersWithRoles = dataUser.usingAdmin().addUsersWithRolesToSite(siteModel, UserRole.SiteManager, UserRole.SiteCollaborator, UserRole.SiteConsumer, UserRole.SiteContributor);
@@ -49,15 +47,40 @@ public class TagsDataPrep extends RestTest
documentTag = restClient.withCoreAPI().usingResource(document).addTag(documentTagValue);
documentTag2 = restClient.withCoreAPI().usingResource(document).addTag(documentTagValue2);
folderTag = restClient.withCoreAPI().usingResource(folder).addTag(folderTagValue);
orphanTag = restClient.withCoreAPI().createSingleTag(RestTagModel.builder().tag(RandomData.getRandomName("orphan-tag")).create());
// Allow indexing to complete.
Utility.sleep(500, 60000, () ->
{
returnedCollection = restClient.withParams("maxItems=10000").withCoreAPI().getTags();
returnedCollection.assertThat().entriesListContains("tag", documentTagValue.toLowerCase())
.and().entriesListContains("tag", documentTagValue2.toLowerCase())
.and().entriesListContains("tag", folderTagValue.toLowerCase());
});
{
returnedCollection = restClient.withParams("maxItems=10000", "where=(tag MATCHES ('*tag*'))")
.withCoreAPI().getTags();
returnedCollection.assertThat().entriesListContains("tag", documentTagValue.toLowerCase())
.and().entriesListContains("tag", documentTagValue2.toLowerCase())
.and().entriesListContains("tag", folderTagValue.toLowerCase());
});
}
protected RestTagModel createTagForDocument(FileModel document)
{
String documentTagValue = RandomData.getRandomName("tag");
return restClient.withCoreAPI().usingResource(document).addTag(documentTagValue);
}
protected RestTagModel createTagModelWithId(final String id)
{
return createTagModelWithIdAndName(id, RandomData.getRandomName("tag"));
}
protected RestTagModel createTagModelWithIdAndName(final String id, final String tag)
{
return RestTagModel.builder()
.id(id)
.tag(tag)
.create();
}
protected RestTagModel createTagModelWithName(final String tagName)
{
return RestTagModel.builder().tag(tagName).create();
}
}

View File

@@ -1,5 +1,7 @@
package org.alfresco.rest.tags;
import static org.alfresco.utility.report.log.Step.STEP;
import org.alfresco.rest.model.RestErrorModel;
import org.alfresco.rest.model.RestTagModel;
import org.alfresco.utility.Utility;
@@ -41,6 +43,7 @@ public class UpdateTagTests extends TagsDataPrep
returnedModel = restClient.withCoreAPI().usingTag(oldTag).update(randomTag);
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedModel.assertThat().field("tag").is(randomTag);
returnedModel.assertThat().field("id").isNotNull();
}
@TestRail(section = { TestGroup.REST_API,
@@ -158,8 +161,8 @@ public class UpdateTagTests extends TagsDataPrep
{
String invalidTagBody = ".\"/<>*";
RestTagModel tag = restClient.authenticateUser(adminUserModel).withCoreAPI().usingResource(document).addTag(RandomData.getRandomName("tag"));
Utility.sleep(500, 20000, () ->
{
Utility.sleep(500, 20000, () ->
{
restClient.withCoreAPI().usingTag(tag).update(invalidTagBody);
restClient.assertStatusCodeIs(HttpStatus.BAD_REQUEST)
.assertLastError().containsSummary(String.format(RestErrorModel.INVALID_TAG, invalidTagBody));
@@ -178,6 +181,7 @@ public class UpdateTagTests extends TagsDataPrep
returnedModel = restClient.withCoreAPI().usingTag(oldTag).update(largeStringTag);
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedModel.assertThat().field("tag").is(largeStringTag);
returnedModel.assertThat().field("id").isNotNull();
}
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
@@ -192,6 +196,7 @@ public class UpdateTagTests extends TagsDataPrep
returnedModel = restClient.withCoreAPI().usingTag(oldTag).update(shortStringTag);
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedModel.assertThat().field("tag").is(shortStringTag);
returnedModel.assertThat().field("id").isNotNull();
}
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
@@ -206,6 +211,7 @@ public class UpdateTagTests extends TagsDataPrep
returnedModel = restClient.withCoreAPI().usingTag(oldTag).update(specialCharsString);
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedModel.assertThat().field("tag").is(specialCharsString);
returnedModel.assertThat().field("id").isNotNull();
}
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
@@ -223,6 +229,7 @@ public class UpdateTagTests extends TagsDataPrep
returnedModel = restClient.withCoreAPI().usingTag(oldExistingTag).update(existingTag);
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedModel.assertThat().field("tag").is(existingTag);
returnedModel.assertThat().field("id").isNotNull();
}
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
@@ -242,6 +249,7 @@ public class UpdateTagTests extends TagsDataPrep
returnedModel = restClient.withCoreAPI().usingTag(newTagModel).update(newTag);
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedModel.assertThat().field("tag").is(newTag);
returnedModel.assertThat().field("id").isNotNull();
}
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
@@ -255,6 +263,7 @@ public class UpdateTagTests extends TagsDataPrep
returnedModel = restClient.authenticateUser(adminUserModel).withCoreAPI().usingTag(oldTag).update(newTag);
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedModel.assertThat().field("tag").is(newTag);
returnedModel.assertThat().field("id").isNotNull();
restClient.withCoreAPI().usingResource(document).deleteTag(returnedModel);
restClient.assertStatusCodeIs(HttpStatus.NO_CONTENT);
@@ -262,4 +271,18 @@ public class UpdateTagTests extends TagsDataPrep
restClient.withCoreAPI().usingResource(document).addTag(newTag);
restClient.assertStatusCodeIs(HttpStatus.CREATED);
}
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.SANITY,
description = "Verify Admin user updates orphan tags and status code is 200")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.SANITY })
public void adminIsAbleToUpdateOrphanTag()
{
STEP("Update orphan tag and expect 200");
final String newTagName = RandomData.getRandomName("new");
returnedModel = restClient.authenticateUser(adminUserModel).withCoreAPI().usingTag(orphanTag).update(newTagName);
restClient.assertStatusCodeIs(HttpStatus.OK);
returnedModel.assertThat().field("tag").is(newTagName);
returnedModel.assertThat().field("id").isNotNull();
}
}

View File

@@ -150,18 +150,6 @@ public class GetNodeTagsTests extends TagsDataPrep
restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND).assertLastError().containsSummary(String.format(RestErrorModel.ENTITY_NOT_FOUND, nodeRef));
}
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "Verify that if node id is empty returns status code 403")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION})
public void emptyNodeIdTest() throws Exception
{
FileModel badDocument = dataContent.usingSite(siteModel).usingUser(adminUserModel).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
badDocument.setNodeRef("");
restClient.authenticateUser(adminUserModel).withCoreAPI().usingResource(badDocument).getNodeTags();
restClient.assertStatusCodeIs(HttpStatus.NOT_FOUND).assertLastError().containsSummary(String.format(RestErrorModel.ENTITY_NOT_FOUND, ""));
}
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
description = "Verify folder tags")
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION})
@@ -303,4 +291,4 @@ public class GetNodeTagsTests extends TagsDataPrep
.and().field("skipCount").is("10000");
returnedCollection.assertThat().entriesListCountIs(0);
}
}
}

View File

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

View File

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

76
pom.xml
View File

@@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>alfresco-community-repo</artifactId>
<version>20.51</version>
<version>20.127</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -35,6 +35,8 @@
<build-number>local</build-number>
<image.tag>latest</image.tag>
<image.registry>quay.io</image.registry>
<builder.name>entitled-builder</builder.name>
<local.registry>127.0.0.1:5000</local.registry>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
@@ -45,26 +47,26 @@
<dependency.alfresco-hb-data-sender.version>1.0.12</dependency.alfresco-hb-data-sender.version>
<dependency.alfresco-trashcan-cleaner.version>2.4.1</dependency.alfresco-trashcan-cleaner.version>
<dependency.alfresco-jlan.version>7.2</dependency.alfresco-jlan.version>
<dependency.alfresco-jlan.version>7.4</dependency.alfresco-jlan.version>
<dependency.alfresco-server-root.version>6.0.1</dependency.alfresco-server-root.version>
<dependency.alfresco-messaging-repo.version>1.2.20</dependency.alfresco-messaging-repo.version>
<dependency.activiti-engine.version>5.23.0</dependency.activiti-engine.version>
<dependency.activiti.version>5.23.0</dependency.activiti.version>
<dependency.alfresco-transform-service.version>2.0.0</dependency.alfresco-transform-service.version>
<dependency.alfresco-transform-core.version>3.0.0</dependency.alfresco-transform-core.version>
<dependency.alfresco-transform-service.version>2.1.0-A2</dependency.alfresco-transform-service.version>
<dependency.alfresco-transform-core.version>3.1.0-A2</dependency.alfresco-transform-core.version>
<dependency.alfresco-greenmail.version>6.5</dependency.alfresco-greenmail.version>
<dependency.acs-event-model.version>0.0.16</dependency.acs-event-model.version>
<dependency.acs-event-model.version>0.0.18</dependency.acs-event-model.version>
<dependency.spring.version>5.3.23</dependency.spring.version>
<dependency.spring.version>5.3.25</dependency.spring.version>
<dependency.antlr.version>3.5.3</dependency.antlr.version>
<dependency.jackson.version>2.14.0</dependency.jackson.version>
<dependency.cxf.version>3.5.4</dependency.cxf.version>
<dependency.jackson.version>2.15.0-rc1</dependency.jackson.version>
<dependency.cxf.version>3.5.5</dependency.cxf.version>
<dependency.opencmis.version>1.0.0</dependency.opencmis.version>
<dependency.webscripts.version>8.33</dependency.webscripts.version>
<dependency.webscripts.version>8.40</dependency.webscripts.version>
<dependency.bouncycastle.version>1.70</dependency.bouncycastle.version>
<dependency.mockito-core.version>4.9.0</dependency.mockito-core.version>
<dependency.assertj.version>3.23.1</dependency.assertj.version>
<dependency.org-json.version>20220320</dependency.org-json.version>
<dependency.assertj.version>3.24.2</dependency.assertj.version>
<dependency.org-json.version>20230227</dependency.org-json.version>
<dependency.commons-dbcp.version>2.9.0</dependency.commons-dbcp.version>
<dependency.commons-io.version>2.11.0</dependency.commons-io.version>
<dependency.gson.version>2.8.9</dependency.gson.version>
@@ -74,20 +76,19 @@
<dependency.xercesImpl.version>2.12.2</dependency.xercesImpl.version>
<dependency.slf4j.version>2.0.3</dependency.slf4j.version>
<dependency.log4j.version>2.19.0</dependency.log4j.version>
<dependency.gytheio.version>0.17</dependency.gytheio.version>
<dependency.groovy.version>3.0.12</dependency.groovy.version>
<dependency.gytheio.version>0.18</dependency.gytheio.version>
<dependency.groovy.version>3.0.16</dependency.groovy.version>
<dependency.tika.version>2.4.1</dependency.tika.version>
<dependency.spring-security.version>5.7.5</dependency.spring-security.version>
<dependency.spring-security.version>5.8.2</dependency.spring-security.version>
<dependency.truezip.version>7.7.10</dependency.truezip.version>
<dependency.poi.version>5.2.2</dependency.poi.version>
<dependency.poi-ooxml-lite.version>5.2.3</dependency.poi-ooxml-lite.version>
<dependency.keycloak.version>18.0.0</dependency.keycloak.version>
<dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version>
<dependency.camel.version>3.18.2</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies -->
<dependency.netty.version>4.1.79.Final</dependency.netty.version> <!-- must be in sync with camels transitive dependencies, e.g.: netty-common -->
<dependency.netty.qpid.version>4.1.72.Final</dependency.netty.qpid.version> <!-- must be in sync with camels transitive dependencies: native-unix-common/native-epoll/native-kqueue -->
<dependency.netty-tcnative.version>2.0.53.Final</dependency.netty-tcnative.version> <!-- must be in sync with camels transitive dependencies -->
<dependency.activemq.version>5.17.1</dependency.activemq.version>
<dependency.camel.version>3.20.2</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies -->
<dependency.netty.version>4.1.87.Final</dependency.netty.version> <!-- must be in sync with camels transitive dependencies, e.g.: netty-common -->
<dependency.netty.qpid.version>4.1.82.Final</dependency.netty.qpid.version> <!-- must be in sync with camels transitive dependencies: native-unix-common/native-epoll/native-kqueue -->
<dependency.netty-tcnative.version>2.0.56.Final</dependency.netty-tcnative.version> <!-- must be in sync with camels transitive dependencies -->
<dependency.activemq.version>5.17.4</dependency.activemq.version>
<dependency.apache-compress.version>1.22</dependency.apache-compress.version>
<dependency.apache.taglibs.version>1.2.5</dependency.apache.taglibs.version>
<dependency.awaitility.version>4.2.0</dependency.awaitility.version>
@@ -107,20 +108,21 @@
<dependency.jakarta-mail-api.version>1.6.5</dependency.jakarta-mail-api.version>
<dependency.jakarta-json-api.version>1.1.6</dependency.jakarta-json-api.version>
<dependency.jakarta-json-path.version>2.7.0</dependency.jakarta-json-path.version>
<dependency.json-smart.version>2.4.8</dependency.json-smart.version>
<dependency.jakarta-rpc-api.version>1.1.4</dependency.jakarta-rpc-api.version>
<alfresco.googledrive.version>3.4.0-A1</alfresco.googledrive.version>
<alfresco.aos-module.version>1.6.0-A1</alfresco.aos-module.version>
<alfresco.googledrive.version>3.4.0-M1</alfresco.googledrive.version>
<alfresco.aos-module.version>1.6.0-A4</alfresco.aos-module.version>
<alfresco.api-explorer.version>7.3.0</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
<alfresco.maven-plugin.version>2.2.0</alfresco.maven-plugin.version>
<license-maven-plugin.version>2.0.1.alfresco-2</license-maven-plugin.version>
<dependency.postgresql.version>42.5.0</dependency.postgresql.version>
<dependency.postgresql.version>42.5.2</dependency.postgresql.version>
<dependency.mysql.version>8.0.30</dependency.mysql.version>
<dependency.mysql-image.version>8</dependency.mysql-image.version>
<dependency.mariadb.version>2.7.4</dependency.mariadb.version>
<dependency.tas-utility.version>3.0.57</dependency.tas-utility.version>
<dependency.tas-utility.version>4.0.0</dependency.tas-utility.version>
<dependency.rest-assured.version>5.2.0</dependency.rest-assured.version>
<dependency.tas-email.version>1.11</dependency.tas-email.version>
<dependency.tas-webdav.version>1.7</dependency.tas-webdav.version>
@@ -148,7 +150,7 @@
<connection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</connection>
<developerConnection>scm:git:https://github.com/Alfresco/alfresco-community-repo.git</developerConnection>
<url>https://github.com/Alfresco/alfresco-community-repo</url>
<tag>20.51</tag>
<tag>20.127</tag>
</scm>
<distributionManagement>
@@ -239,6 +241,17 @@
<version>${dependency.jakarta-json-api.version}</version>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<version>${dependency.jakarta-json-path.version}</version>
</dependency>
<dependency>
<groupId> net.minidev</groupId>
<artifactId>json-smart</artifactId>
<version>${dependency.json-smart.version}</version>
</dependency>
<dependency>
<groupId>jakarta.xml.rpc</groupId>
<artifactId>jakarta.xml.rpc-api</artifactId>
@@ -384,7 +397,7 @@
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
<version>1.5</version>
</dependency>
<dependency>
@@ -516,7 +529,7 @@
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.32</version>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
@@ -899,6 +912,13 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-bom</artifactId>
<version>${dependency.spring-security.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
@@ -916,7 +936,7 @@
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.40.2</version>
<version>0.42.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>

View File

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

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -26,31 +26,101 @@
package org.alfresco.rest.api;
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
import java.util.List;
import org.alfresco.rest.api.model.Category;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.StoreRef;
@Experimental
public interface Categories
{
Category getCategoryById(String id, Parameters parameters);
Category getCategoryById(StoreRef storeRef, String id, Parameters parameters);
List<Category> createSubcategories(String parentCategoryId, List<Category> categories, Parameters parameters);
default Category getCategoryById(String id, Parameters parameters)
{
return getCategoryById(STORE_REF_WORKSPACE_SPACESSTORE, id, parameters);
}
CollectionWithPagingInfo<Category> getCategoryChildren(String parentCategoryId, Parameters parameters);
List<Category> createSubcategories(StoreRef storeRef, String parentCategoryId, List<Category> categories, Parameters parameters);
default List<Category> createSubcategories(String parentCategoryId, List<Category> categories, Parameters parameters)
{
return createSubcategories(STORE_REF_WORKSPACE_SPACESSTORE, parentCategoryId, categories, parameters);
}
List<Category> getCategoryChildren(StoreRef storeRef, String parentCategoryId, Parameters parameters);
default List<Category> getCategoryChildren(String parentCategoryId, Parameters parameters)
{
return getCategoryChildren(STORE_REF_WORKSPACE_SPACESSTORE, parentCategoryId, parameters);
}
/**
* Update category by ID. Currently, it's possible only to update the name of category.
*
* @param storeRef Reference to node store.
* @param id Category ID.
* @param fixedCategoryModel Fixed category model.
* @param parameters Additional parameters.
* @return Updated category.
*/
Category updateCategoryById(String id, Category fixedCategoryModel);
Category updateCategoryById(StoreRef storeRef, String id, Category fixedCategoryModel, Parameters parameters);
void deleteCategoryById(String id, Parameters parameters);
default Category updateCategoryById(String id, Category fixedCategoryModel, Parameters parameters)
{
return updateCategoryById(STORE_REF_WORKSPACE_SPACESSTORE, id, fixedCategoryModel, parameters);
}
void deleteCategoryById(StoreRef storeRef, String id, Parameters parameters);
default void deleteCategoryById(String id, Parameters parameters)
{
deleteCategoryById(STORE_REF_WORKSPACE_SPACESSTORE, id, parameters);
}
/**
* Get categories linked from node. Read permission on node is required.
* Node type is restricted to specified vales from: {@link org.alfresco.util.TypeConstraint}.
*
* @param nodeId Node ID.
* @param parameters Additional parameters.
* @return Categories linked from node.
*/
List<Category> listCategoriesForNode(String nodeId, Parameters parameters);
/**
* Link node to categories. Change permission on node is required.
* Node types allowed for categorization are specified within {@link org.alfresco.util.TypeConstraint}.
*
* @param storeRef Reference to node store.
* @param nodeId Node ID.
* @param categoryLinks Category IDs to which content should be linked to.
* @param parameters Additional parameters.
* @return Linked to categories.
*/
List<Category> linkNodeToCategories(StoreRef storeRef, String nodeId, List<Category> categoryLinks, Parameters parameters);
default List<Category> linkNodeToCategories(String nodeId, List<Category> categoryLinks, Parameters parameters)
{
return linkNodeToCategories(STORE_REF_WORKSPACE_SPACESSTORE, nodeId, categoryLinks, parameters);
}
/**
* Unlink node from a category.
*
* @param storeRef Reference to node store.
* @param nodeId Node ID.
* @param categoryId Category ID from which content node should be unlinked from.
* @param parameters Additional parameters.
*/
void unlinkNodeFromCategory(StoreRef storeRef, String nodeId, String categoryId, Parameters parameters);
default void unlinkNodeFromCategory(String nodeId, String categoryId, Parameters parameters)
{
unlinkNodeFromCategory(STORE_REF_WORKSPACE_SPACESSTORE, nodeId, categoryId, parameters);
}
}

View File

@@ -39,6 +39,8 @@ import org.alfresco.rest.api.model.LockInfo;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.api.model.PathInfo;
import org.alfresco.rest.api.model.UserInfo;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.resource.content.BasicContentInfo;
import org.alfresco.rest.framework.resource.content.BinaryResource;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
@@ -208,6 +210,19 @@ public interface Nodes
NodeRef validateNode(StoreRef storeRef, String nodeId);
NodeRef validateNode(String nodeId);
NodeRef validateNode(NodeRef nodeRef);
/**
* Check that the specified id refers to a valid node.
*
* @param nodeId The node id to look up using SpacesStore or an alias like -root-.
* @return The node ref.
* @throws InvalidArgumentException if the specified node id is not a valid format.
* @throws EntityNotFoundException if the specified node was not found in the database.
*/
default NodeRef validateOrLookupNode(String nodeId)
{
return validateOrLookupNode(nodeId, null);
}
NodeRef validateOrLookupNode(String nodeId, String path);
boolean nodeMatches(NodeRef nodeRef, Set<QName> expectedTypes, Set<QName> excludedTypes);

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -23,22 +23,35 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.api;
import java.util.List;
import org.alfresco.rest.api.model.Tag;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.cmr.repository.StoreRef;
public interface Tags
{
public List<Tag> addTags(String nodeId, List<Tag> tags);
public Tag getTag(StoreRef storeRef, String tagId);
public void deleteTag(String nodeId, String tagId);
public CollectionWithPagingInfo<Tag> getTags(StoreRef storeRef, Parameters params);
public Tag changeTag(StoreRef storeRef, String tagId, Tag tag);
public CollectionWithPagingInfo<Tag> getTags(String nodeId, Parameters params);
}
package org.alfresco.rest.api;
import static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
import java.util.List;
import org.alfresco.rest.api.model.Tag;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.StoreRef;
public interface Tags
{
List<Tag> addTags(String nodeId, List<Tag> tags, Parameters parameters);
Tag getTag(StoreRef storeRef, String tagId);
void deleteTag(String nodeId, String tagId);
CollectionWithPagingInfo<Tag> getTags(StoreRef storeRef, Parameters params);
Tag changeTag(StoreRef storeRef, String tagId, Tag tag);
CollectionWithPagingInfo<Tag> getTags(String nodeId, Parameters params);
@Experimental
List<Tag> createTags(StoreRef storeRef, List<Tag> tags, Parameters parameters);
@Experimental
default List<Tag> createTags(List<Tag> tags, Parameters parameters)
{
return createTags(STORE_REF_WORKSPACE_SPACESSTORE, tags, parameters);
}
void deleteTagById(StoreRef storeRef, String tagId);
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -45,6 +45,7 @@ public class CategoriesEntityResource implements EntityResourceAction.ReadById<C
EntityResourceAction.Update<Category>,
EntityResourceAction.Delete
{
private final Categories categories;
public CategoriesEntityResource(Categories categories)
@@ -77,7 +78,7 @@ public class CategoriesEntityResource implements EntityResourceAction.ReadById<C
@Override
public Category update(String id, Category categoryModel, Parameters parameters)
{
return categories.updateCategoryById(id, categoryModel);
return categories.updateCategoryById(id, categoryModel, parameters);
}
/**

View File

@@ -0,0 +1,96 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.api.categories;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import org.alfresco.rest.api.Categories;
import org.alfresco.rest.api.model.Category;
import org.alfresco.rest.api.nodes.NodesEntityResource;
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.ListPage;
import org.alfresco.rest.framework.resource.parameters.Parameters;
@RelationshipResource(name = "category-links", entityResource = NodesEntityResource.class, title = "Category links")
public class NodesCategoryLinksRelation implements RelationshipResourceAction.Create<Category>,
RelationshipResourceAction.Read<Category>,
RelationshipResourceAction.Delete
{
private final Categories categories;
public NodesCategoryLinksRelation(Categories categories)
{
this.categories = categories;
}
/**
* GET /nodes/{nodeId}/category-links
*/
@WebApiDescription(
title = "Get categories linked to by node",
description = "Get categories linked to by node",
successStatus = HttpServletResponse.SC_OK
)
@Override
public CollectionWithPagingInfo<Category> readAll(String nodeId, Parameters parameters)
{
return ListPage.of(categories.listCategoriesForNode(nodeId, parameters), parameters.getPaging());
}
/**
* POST /nodes/{nodeId}/category-links
*/
@WebApiDescription(
title = "Link node to categories",
description = "Creates a link between a node and categories",
successStatus = HttpServletResponse.SC_CREATED
)
@Override
public List<Category> create(String nodeId, List<Category> categoryLinks, Parameters parameters)
{
return categories.linkNodeToCategories(nodeId, categoryLinks, parameters);
}
/**
* DELETE /nodes/{nodeId}/category-links/{categoryId}
*/
@WebApiDescription(
title = "Unlink content node from category",
description = "Removes the link between a content node and a category",
successStatus = HttpServletResponse.SC_NO_CONTENT
)
@Override
public void delete(String nodeId, String categoryId, Parameters parameters)
{
categories.unlinkNodeFromCategory(nodeId, categoryId, parameters);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -26,9 +26,8 @@
package org.alfresco.rest.api.categories;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import org.alfresco.rest.api.Categories;
import org.alfresco.rest.api.model.Category;
@@ -36,6 +35,7 @@ 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.ListPage;
import org.alfresco.rest.framework.resource.parameters.Parameters;
@RelationshipResource(name = "subcategories", entityResource = CategoriesEntityResource.class, title = "Subcategories")
@@ -69,8 +69,8 @@ public class SubcategoriesRelation implements RelationshipResourceAction.Create<
description = "Lists direct children of a parent category",
successStatus = HttpServletResponse.SC_OK)
@Override
public CollectionWithPagingInfo<Category> readAll(String parentCategoryId, Parameters params)
public CollectionWithPagingInfo<Category> readAll(String parentCategoryId, Parameters parameters)
{
return categories.getCategoryChildren(parentCategoryId, params);
return ListPage.of(categories.getCategoryChildren(parentCategoryId, parameters), parameters.getPaging());
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -27,8 +27,16 @@
package org.alfresco.rest.api.impl;
import static org.alfresco.rest.api.Nodes.PATH_ROOT;
import static org.alfresco.service.cmr.security.AccessStatus.ALLOWED;
import static org.alfresco.service.cmr.security.PermissionService.CHANGE_PERMISSIONS;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.alfresco.model.ContentModel;
@@ -38,101 +46,138 @@ import org.alfresco.rest.api.model.Category;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.core.exceptions.EntityNotFoundException;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
import org.alfresco.rest.framework.core.exceptions.InvalidNodeTypeException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.ListPage;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.search.CategoryService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.RegexQNamePattern;
import org.alfresco.util.Pair;
import org.alfresco.util.TypeConstraint;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
@Experimental
public class CategoriesImpl implements Categories
{
static final String INCLUDE_COUNT_PARAM = "count";
static final String NOT_A_VALID_CATEGORY = "Node id does not refer to a valid category";
static final String NO_PERMISSION_TO_MANAGE_A_CATEGORY = "Current user does not have permission to manage a category";
static final String NO_PERMISSION_TO_READ_CONTENT = "Current user does not have read permission to content";
static final String NO_PERMISSION_TO_CHANGE_CONTENT = "Current user does not have change permission to content";
static final String NOT_NULL_OR_EMPTY = "Category name must not be null or empty";
static final String FIELD_NOT_MATCH = "Category field: %s does not match the original one";
static final String INVALID_NODE_TYPE = "Cannot categorize this type of node";
private final AuthorityService authorityService;
private final CategoryService categoryService;
private final Nodes nodes;
private final NodeService nodeService;
private final PermissionService permissionService;
private final TypeConstraint typeConstraint;
public CategoriesImpl(AuthorityService authorityService, CategoryService categoryService, Nodes nodes, NodeService nodeService)
public CategoriesImpl(AuthorityService authorityService, CategoryService categoryService, Nodes nodes, NodeService nodeService,
PermissionService permissionService, TypeConstraint typeConstraint)
{
this.authorityService = authorityService;
this.categoryService = categoryService;
this.nodes = nodes;
this.nodeService = nodeService;
this.permissionService = permissionService;
this.typeConstraint = typeConstraint;
}
@Override
public Category getCategoryById(final String id, final Parameters params)
public Category getCategoryById(final StoreRef storeRef, final String id, final Parameters parameters)
{
final NodeRef nodeRef = getCategoryNodeRef(id);
final NodeRef nodeRef = getCategoryNodeRef(storeRef, id);
if (isRootCategory(nodeRef))
{
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{id});
}
return mapToCategory(nodeRef);
final Category category = mapToCategory(nodeRef);
if (parameters.getInclude().contains(INCLUDE_COUNT_PARAM))
{
final Map<String, Integer> categoriesCount = getCategoriesCount(storeRef);
category.setCount(categoriesCount.getOrDefault(category.getId(), 0));
}
return category;
}
@Override
public List<Category> createSubcategories(String parentCategoryId, List<Category> categories, Parameters parameters)
public List<Category> createSubcategories(final StoreRef storeRef, final String parentCategoryId, final List<Category> categories, final Parameters parameters)
{
verifyAdminAuthority();
final NodeRef parentNodeRef = getCategoryNodeRef(parentCategoryId);
final List<NodeRef> categoryNodeRefs = categories.stream()
final NodeRef parentNodeRef = getCategoryNodeRef(storeRef, parentCategoryId);
return categories.stream()
.map(c -> createCategoryNodeRef(parentNodeRef, c))
.collect(Collectors.toList());
return categoryNodeRefs.stream()
.map(this::mapToCategory)
.peek(category -> {
if (parameters.getInclude().contains(INCLUDE_COUNT_PARAM))
{
category.setCount(0);
}
})
.collect(Collectors.toList());
}
@Override
public CollectionWithPagingInfo<Category> getCategoryChildren(String parentCategoryId, Parameters params)
public List<Category> getCategoryChildren(final StoreRef storeRef, final String parentCategoryId, final Parameters parameters)
{
final NodeRef parentNodeRef = getCategoryNodeRef(parentCategoryId);
final List<ChildAssociationRef> childCategoriesAssocs = nodeService.getChildAssocs(parentNodeRef).stream()
.filter(ca -> ContentModel.ASSOC_SUBCATEGORIES.equals(ca.getTypeQName()))
.collect(Collectors.toList());
final List<Category> categories = childCategoriesAssocs.stream()
.map(c -> mapToCategory(c.getChildRef()))
.collect(Collectors.toList());
return ListPage.of(categories, params.getPaging());
final NodeRef parentNodeRef = getCategoryNodeRef(storeRef, parentCategoryId);
final List<Category> categories = nodeService.getChildAssocs(parentNodeRef).stream()
.filter(ca -> ContentModel.ASSOC_SUBCATEGORIES.equals(ca.getTypeQName()))
.map(ChildAssociationRef::getChildRef)
.map(this::mapToCategory)
.collect(Collectors.toList());
if (parameters.getInclude().contains(INCLUDE_COUNT_PARAM))
{
final Map<String, Integer> categoriesCount = getCategoriesCount(storeRef);
categories.forEach(category -> category.setCount(categoriesCount.getOrDefault(category.getId(), 0)));
}
return categories;
}
@Override
public Category updateCategoryById(final String id, final Category fixedCategoryModel)
public Category updateCategoryById(final StoreRef storeRef, final String id, final Category fixedCategoryModel, final Parameters parameters)
{
verifyAdminAuthority();
final NodeRef categoryNodeRef = getCategoryNodeRef(id);
final NodeRef categoryNodeRef = getCategoryNodeRef(storeRef, id);
if (isRootCategory(categoryNodeRef))
{
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{id});
}
verifyCategoryFields(fixedCategoryModel);
validateCategoryFields(fixedCategoryModel);
final Category category = mapToCategory(changeCategoryName(categoryNodeRef, fixedCategoryModel.getName()));
return mapToCategory(changeCategoryName(categoryNodeRef, fixedCategoryModel.getName()));
if (parameters.getInclude().contains(INCLUDE_COUNT_PARAM))
{
final Map<String, Integer> categoriesCount = getCategoriesCount(storeRef);
category.setCount(categoriesCount.getOrDefault(category.getId(), 0));
}
return category;
}
@Override
public void deleteCategoryById(String id, Parameters parameters)
public void deleteCategoryById(final StoreRef storeRef, final String id, final Parameters parameters)
{
verifyAdminAuthority();
final NodeRef nodeRef = getCategoryNodeRef(id);
final NodeRef nodeRef = getCategoryNodeRef(storeRef, id);
if (isRootCategory(nodeRef))
{
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{id});
@@ -141,6 +186,82 @@ public class CategoriesImpl implements Categories
nodeService.deleteNode(nodeRef);
}
@Override
public List<Category> listCategoriesForNode(final String nodeId, final Parameters parameters)
{
final NodeRef contentNodeRef = nodes.validateOrLookupNode(nodeId);
verifyReadPermission(contentNodeRef);
verifyNodeType(contentNodeRef);
final Serializable currentCategories = nodeService.getProperty(contentNodeRef, ContentModel.PROP_CATEGORIES);
if (currentCategories == null)
{
return Collections.emptyList();
}
final Collection<NodeRef> actualCategories = DefaultTypeConverter.INSTANCE.getCollection(NodeRef.class, currentCategories);
return actualCategories.stream().map(this::mapToCategory).collect(Collectors.toList());
}
@Override
public List<Category> linkNodeToCategories(final StoreRef storeRef, final String nodeId, final List<Category> categoryLinks, final Parameters parameters)
{
if (CollectionUtils.isEmpty(categoryLinks))
{
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY);
}
final NodeRef contentNodeRef = nodes.validateOrLookupNode(nodeId);
verifyChangePermission(contentNodeRef);
verifyNodeType(contentNodeRef);
final Collection<NodeRef> categoryNodeRefs = categoryLinks.stream()
.filter(Objects::nonNull)
.map(Category::getId)
.filter(StringUtils::isNotEmpty)
.distinct()
.map(id -> getCategoryNodeRef(storeRef, id))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(categoryNodeRefs) || isRootCategoryPresent(categoryNodeRefs))
{
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY);
}
linkNodeToCategories(contentNodeRef, categoryNodeRefs);
return categoryNodeRefs.stream().map(this::mapToCategory).collect(Collectors.toList());
}
@Override
public void unlinkNodeFromCategory(final StoreRef storeRef, final String nodeId, final String categoryId, final Parameters parameters)
{
final NodeRef categoryNodeRef = getCategoryNodeRef(storeRef, categoryId);
final NodeRef contentNodeRef = nodes.validateOrLookupNode(nodeId);
verifyChangePermission(contentNodeRef);
verifyNodeType(contentNodeRef);
if (isCategoryAspectMissing(contentNodeRef))
{
throw new InvalidArgumentException("Node with id: " + nodeId + " does not belong to a category");
}
if (isRootCategory(categoryNodeRef))
{
throw new InvalidArgumentException(NOT_A_VALID_CATEGORY, new String[]{categoryId});
}
final Collection<NodeRef> allCategories = removeCategory(contentNodeRef, categoryNodeRef);
if (allCategories.size()==0)
{
nodeService.removeAspect(contentNodeRef, ContentModel.ASPECT_GEN_CLASSIFIABLE);
nodeService.removeProperty(contentNodeRef, ContentModel.PROP_CATEGORIES);
return;
}
nodeService.setProperty(contentNodeRef, ContentModel.PROP_CATEGORIES, (Serializable) allCategories);
}
private void verifyAdminAuthority()
{
if (!authorityService.hasAdminAuthority())
@@ -149,17 +270,42 @@ public class CategoriesImpl implements Categories
}
}
private void verifyReadPermission(final NodeRef nodeRef)
{
if (permissionService.hasReadPermission(nodeRef) != ALLOWED)
{
throw new PermissionDeniedException(NO_PERMISSION_TO_READ_CONTENT);
}
}
private void verifyChangePermission(final NodeRef nodeRef)
{
if (permissionService.hasPermission(nodeRef, CHANGE_PERMISSIONS) != ALLOWED)
{
throw new PermissionDeniedException(NO_PERMISSION_TO_CHANGE_CONTENT);
}
}
private void verifyNodeType(final NodeRef nodeRef)
{
if (!typeConstraint.matches(nodeRef))
{
throw new InvalidNodeTypeException(INVALID_NODE_TYPE);
}
}
/**
* This method gets category NodeRef for a given category id.
* If '-root-' is passed as category id, then it's retrieved as a call to {@link org.alfresco.service.cmr.search.CategoryService#getRootCategoryNodeRef}
* In all other cases it's retrieved as a node of a category type {@link #validateCategoryNode(String)}
* @param storeRef Reference to node store.
* @param nodeId category node id
* @return NodRef of category node
*/
private NodeRef getCategoryNodeRef(String nodeId)
private NodeRef getCategoryNodeRef(StoreRef storeRef, String nodeId)
{
return PATH_ROOT.equals(nodeId) ?
categoryService.getRootCategoryNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE)
categoryService.getRootCategoryNodeRef(storeRef)
.orElseThrow(() -> new EntityNotFoundException(nodeId)) :
validateCategoryNode(nodeId);
}
@@ -181,7 +327,7 @@ public class CategoriesImpl implements Categories
private NodeRef createCategoryNodeRef(NodeRef parentNodeRef, Category c)
{
verifyCategoryFields(c);
validateCategoryFields(c);
return categoryService.createCategory(parentNodeRef, c.getName());
}
@@ -236,15 +382,97 @@ public class CategoriesImpl implements Categories
}
/**
* Verify if fixed category name is not empty.
* Validate if fixed category name is not empty.
*
* @param fixedCategoryModel Fixed category model.
*/
private void verifyCategoryFields(final Category fixedCategoryModel)
private void validateCategoryFields(final Category fixedCategoryModel)
{
if (StringUtils.isEmpty(fixedCategoryModel.getName()))
{
throw new InvalidArgumentException(NOT_NULL_OR_EMPTY);
}
}
private boolean isRootCategoryPresent(final Collection<NodeRef> categoryNodeRefs)
{
return categoryNodeRefs.stream().anyMatch(this::isRootCategory);
}
private boolean isCategoryAspectMissing(final NodeRef nodeRef)
{
return !nodeService.hasAspect(nodeRef, ContentModel.ASPECT_GEN_CLASSIFIABLE);
}
/**
* Merge already present and new categories ignoring repeating ones.
*
* @param currentCategories Already present categories.
* @param newCategories Categories which should be added.
* @return Merged categories.
*/
private Collection<NodeRef> mergeCategories(final Serializable currentCategories, final Collection<NodeRef> newCategories)
{
if (currentCategories == null)
{
return newCategories;
}
final Collection<NodeRef> actualCategories = DefaultTypeConverter.INSTANCE.getCollection(NodeRef.class, currentCategories);
final Collection<NodeRef> allCategories = new HashSet<>(actualCategories);
allCategories.addAll(newCategories);
return allCategories;
}
/**
* Remove specified category from present categories.
* @param contentNodeRef the nodeRef that contains the categories.
* @param categoryToRemove category that should be removed.
* @return updated category list.
*/
private Collection<NodeRef> removeCategory(final NodeRef contentNodeRef, final NodeRef categoryToRemove)
{
final Serializable currentCategories = nodeService.getProperty(contentNodeRef, ContentModel.PROP_CATEGORIES);
final Collection<NodeRef> actualCategories = DefaultTypeConverter.INSTANCE.getCollection(NodeRef.class, currentCategories);
final Collection<NodeRef> updatedCategories = new HashSet<>(actualCategories);
updatedCategories.remove(categoryToRemove);
return updatedCategories;
}
/**
* Add to or update node's property cm:categories containing linked category references.
*
* @param nodeRef Node reference.
* @param categoryNodeRefs Category node references.
*/
private void linkNodeToCategories(final NodeRef nodeRef, final Collection<NodeRef> categoryNodeRefs)
{
if (isCategoryAspectMissing(nodeRef))
{
final Map<QName, Serializable> properties = Map.of(ContentModel.PROP_CATEGORIES, (Serializable) categoryNodeRefs);
nodeService.addAspect(nodeRef, ContentModel.ASPECT_GEN_CLASSIFIABLE, properties);
}
else
{
final Serializable currentCategories = nodeService.getProperty(nodeRef, ContentModel.PROP_CATEGORIES);
final Collection<NodeRef> allCategories = mergeCategories(currentCategories, categoryNodeRefs);
nodeService.setProperty(nodeRef, ContentModel.PROP_CATEGORIES, (Serializable) allCategories);
}
}
/**
* Get categories by usage count. Result is a map of category IDs (short form - UUID) as key and usage count as value.
*
* @param storeRef Reference to node store.
* @return Map of categories IDs and usage count.
*/
private Map<String, Integer> getCategoriesCount(final StoreRef storeRef)
{
final String idPrefix = storeRef + "/";
return categoryService.getTopCategories(storeRef, ContentModel.ASPECT_GEN_CLASSIFIABLE, Integer.MAX_VALUE)
.stream()
.collect(Collectors.toMap(pair -> pair.getFirst().toString().replace(idPrefix, StringUtils.EMPTY), Pair::getSecond));
}
}

View File

@@ -1356,7 +1356,7 @@ public class NodesImpl implements Nodes
private void calculateRelativePath(String parentFolderNodeId, Node node)
{
NodeRef rootNodeRef = validateOrLookupNode(parentFolderNodeId, null);
NodeRef rootNodeRef = validateOrLookupNode(parentFolderNodeId);
try
{
// get the path elements
@@ -1741,7 +1741,7 @@ public class NodesImpl implements Nodes
@Override
public void deleteNode(String nodeId, Parameters parameters)
{
NodeRef nodeRef = validateOrLookupNode(nodeId, null);
NodeRef nodeRef = validateOrLookupNode(nodeId);
if (isSpecialNode(nodeRef, getNodeType(nodeRef)))
{
@@ -1785,7 +1785,7 @@ public class NodesImpl implements Nodes
validateProperties(nodeInfo.getProperties(), EXCLUDED_NS, Arrays.asList());
// check that requested parent node exists and it's type is a (sub-)type of folder
NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, null);
NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId);
// node name - mandatory
String nodeName = nodeInfo.getName();
@@ -2290,7 +2290,7 @@ public class NodesImpl implements Nodes
validateAspects(nodeInfo.getAspectNames(), EXCLUDED_NS, EXCLUDED_ASPECTS);
validateProperties(nodeInfo.getProperties(), EXCLUDED_NS, Arrays.asList());
final NodeRef nodeRef = validateOrLookupNode(nodeId, null);
final NodeRef nodeRef = validateOrLookupNode(nodeId);
QName nodeTypeQName = getNodeType(nodeRef);
@@ -2402,6 +2402,9 @@ public class NodesImpl implements Nodes
// Check inherit from parent value and if it's changed set the new value
if (nodePerms.getIsInheritanceEnabled() != null)
{
// If inheritance flag is being disabled, the site manager needs to have permission
setSiteManagerPermission(nodeRef, nodePerms);
if (nodePerms.getIsInheritanceEnabled() != permissionService.getInheritParentPermissions(nodeRef))
{
permissionService.setInheritParentPermissions(nodeRef, nodePerms.getIsInheritanceEnabled());
@@ -2520,8 +2523,8 @@ public class NodesImpl implements Nodes
throw new InvalidArgumentException("Missing targetParentId");
}
final NodeRef parentNodeRef = validateOrLookupNode(targetParentId, null);
final NodeRef sourceNodeRef = validateOrLookupNode(sourceNodeId, null);
final NodeRef parentNodeRef = validateOrLookupNode(targetParentId);
final NodeRef sourceNodeRef = validateOrLookupNode(sourceNodeId);
FileInfo fi = moveOrCopyImpl(sourceNodeRef, parentNodeRef, name, isCopy);
return getFolderOrDocument(fi.getNodeRef().getId(), parameters);
@@ -2763,6 +2766,34 @@ public class NodesImpl implements Nodes
return updateExistingFile(null, nodeRef, fileName, contentInfo, stream, parameters, versionMajor, versionComment);
}
private void setSiteManagerPermission(NodeRef nodeRef, NodePermissions nodePerms)
{
if (nodeRef != null && nodePerms != null)
{
try
{
if (nodePerms.getIsInheritanceEnabled() != null && !nodePerms.getIsInheritanceEnabled())
{
SiteInfo containingSite = siteService.getSite(nodeRef);
if (containingSite != null)
{
String thisSiteGroupPrefix = siteService.getSiteGroup(containingSite.getShortName());
final String siteManagerAuthority = thisSiteGroupPrefix + "_" + SiteModel.SITE_MANAGER;
AuthenticationUtil.runAsSystem(() -> {
permissionService.setPermission(nodeRef, siteManagerAuthority, SiteModel.SITE_MANAGER, true);
return null;
});
}
}
}
catch (Exception e)
{
logger.error("Error setting site manager permission on " + nodeRef, e);
}
}
}
private Node updateExistingFile(NodeRef parentNodeRef, NodeRef nodeRef, String fileName, BasicContentInfo contentInfo, InputStream stream, Parameters parameters, Boolean versionMajor, String versionComment)
{
boolean isVersioned = versionService.isVersioned(nodeRef);
@@ -2923,7 +2954,7 @@ public class NodesImpl implements Nodes
throw new InvalidArgumentException("The request content-type is not multipart: "+parentFolderNodeId);
}
NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId, null);
NodeRef parentNodeRef = validateOrLookupNode(parentFolderNodeId);
if (!nodeMatches(parentNodeRef, Collections.singleton(ContentModel.TYPE_FOLDER), null, false))
{
throw new InvalidArgumentException("NodeId of folder is expected: " + parentNodeRef.getId());
@@ -3354,7 +3385,7 @@ public class NodesImpl implements Nodes
@Override
public Node lock(String nodeId, LockInfo lockInfo, Parameters parameters)
{
NodeRef nodeRef = validateOrLookupNode(nodeId, null);
NodeRef nodeRef = validateOrLookupNode(nodeId);
if (isSpecialNode(nodeRef, getNodeType(nodeRef)))
{
@@ -3393,7 +3424,7 @@ public class NodesImpl implements Nodes
@Override
public Node unlock(String nodeId, Parameters parameters)
{
NodeRef nodeRef = validateOrLookupNode(nodeId, null);
NodeRef nodeRef = validateOrLookupNode(nodeId);
if (isSpecialNode(nodeRef, getNodeType(nodeRef)))
{

View File

@@ -185,7 +185,7 @@ public class QueriesImpl implements Queries, InitializingBean
String rootNodeId = parameters.getParameter(PARAM_ROOT_NODE_ID);
if (rootNodeId != null)
{
NodeRef nodeRef = nodes.validateOrLookupNode(rootNodeId, null);
NodeRef nodeRef = nodes.validateOrLookupNode(rootNodeId);
query.append("PATH:\"").append(getQNamePath(nodeRef.getId())).append("//*\" AND (");
}
if (term != null)

View File

@@ -695,7 +695,7 @@ public class RenditionsImpl implements Renditions, ResourceLoaderAware
{
if (versionLabelId != null)
{
nodeRef = nodes.validateOrLookupNode(nodeRef.getId(), null);
nodeRef = nodes.validateOrLookupNode(nodeRef.getId());
VersionHistory vh = versionService.getVersionHistory(nodeRef);
if (vh != null)
{

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -23,125 +23,166 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.api.impl;
import java.util.AbstractList;
package org.alfresco.rest.api.impl;
import static java.util.stream.Collectors.toList;
import static org.alfresco.rest.antlr.WhereClauseParser.EQUALS;
import static org.alfresco.rest.antlr.WhereClauseParser.IN;
import static org.alfresco.rest.antlr.WhereClauseParser.MATCHES;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
import org.alfresco.query.PagingResults;
import org.alfresco.repo.tagging.NonExistentTagException;
import org.alfresco.repo.tagging.TagExistsException;
import org.alfresco.repo.tagging.TaggingException;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.Tags;
import org.alfresco.rest.api.model.Tag;
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.rest.framework.core.exceptions.NotFoundException;
import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.util.Pair;
import org.alfresco.util.TypeConstraint;
/**
* Centralises access to tag services and maps between representations.
*
* @author steveglover
* @since publicapi1.0
*/
public class TagsImpl implements Tags
{
private static final Object PARAM_INCLUDE_COUNT = "count";
private Nodes nodes;
private TaggingService taggingService;
private TypeConstraint typeConstraint;
public void setTypeConstraint(TypeConstraint typeConstraint)
{
this.typeConstraint = typeConstraint;
}
public void setNodes(Nodes nodes)
{
this.nodes = nodes;
}
public void setTaggingService(TaggingService taggingService)
{
this.taggingService = taggingService;
}
public List<Tag> addTags(String nodeId, final List<Tag> tags)
{
NodeRef nodeRef = nodes.validateNode(nodeId);
if(!typeConstraint.matches(nodeRef))
{
throw new UnsupportedResourceOperationException("Cannot tag this node");
}
List<String> tagValues = new AbstractList<String>()
{
@Override
public String get(int arg0)
{
String tag = tags.get(arg0).getTag();
return tag;
}
@Override
public int size()
{
return tags.size();
}
};
try
{
List<Pair<String, NodeRef>> tagNodeRefs = taggingService.addTags(nodeRef, tagValues);
List<Tag> ret = new ArrayList<Tag>(tags.size());
for(Pair<String, NodeRef> pair : tagNodeRefs)
{
ret.add(new Tag(pair.getSecond(), pair.getFirst()));
}
return ret;
}
catch(IllegalArgumentException e)
{
throw new InvalidArgumentException(e.getMessage());
}
}
public void deleteTag(String nodeId, String tagId)
{
NodeRef nodeRef = nodes.validateNode(nodeId);
getTag(tagId);
NodeRef existingTagNodeRef = validateTag(tagId);
String tagValue = taggingService.getTagName(existingTagNodeRef);
taggingService.removeTag(nodeRef, tagValue);
}
import org.alfresco.query.PagingResults;
import org.alfresco.repo.tagging.NonExistentTagException;
import org.alfresco.repo.tagging.TagExistsException;
import org.alfresco.repo.tagging.TaggingException;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.Tags;
import org.alfresco.rest.api.model.Tag;
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.rest.framework.core.exceptions.NotFoundException;
import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationException;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Paging;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.rest.framework.resource.parameters.where.Query;
import org.alfresco.rest.framework.resource.parameters.where.QueryHelper;
import org.alfresco.rest.framework.resource.parameters.where.QueryImpl;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.tagging.TaggingService;
import org.alfresco.util.Pair;
import org.alfresco.util.TypeConstraint;
import org.apache.commons.collections.CollectionUtils;
/**
* Centralises access to tag services and maps between representations.
*
* @author steveglover
* @since publicapi1.0
*/
public class TagsImpl implements Tags
{
private static final String PARAM_INCLUDE_COUNT = "count";
private static final String PARAM_WHERE_TAG = "tag";
static final String NOT_A_VALID_TAG = "An invalid parameter has been supplied";
static final String NO_PERMISSION_TO_MANAGE_A_TAG = "Current user does not have permission to manage a tag";
private final NodeRef tagParentNodeRef = new NodeRef("workspace://SpacesStore/tag:tag-root");
private Nodes nodes;
private NodeService nodeService;
private TaggingService taggingService;
private TypeConstraint typeConstraint;
private AuthorityService authorityService;
public void setTypeConstraint(TypeConstraint typeConstraint)
{
this.typeConstraint = typeConstraint;
}
public void setNodes(Nodes nodes)
{
this.nodes = nodes;
}
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void setTaggingService(TaggingService taggingService)
{
this.taggingService = taggingService;
}
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
public List<Tag> addTags(String nodeId, final List<Tag> tags, final Parameters parameters)
{
NodeRef nodeRef = nodes.validateOrLookupNode(nodeId);
if (!typeConstraint.matches(nodeRef))
{
throw new UnsupportedResourceOperationException("Cannot tag this node");
}
List<String> tagValues = tags.stream().map(Tag::getTag).collect(toList());
try
{
List<Pair<String, NodeRef>> tagNodeRefs = taggingService.addTags(nodeRef, tagValues);
List<Tag> ret = new ArrayList<>(tags.size());
List<Pair<String, Integer>> tagsCountPairList = taggingService.findTaggedNodesAndCountByTagName(nodeRef.getStoreRef());
Map<String, Integer> tagsCountMap = tagsCountPairList.stream().collect(Collectors.toMap(Pair::getFirst,Pair::getSecond));
for (Pair<String, NodeRef> pair : tagNodeRefs)
{
Tag createdTag = new Tag(pair.getSecond(), pair.getFirst());
if (parameters.getInclude().contains(PARAM_INCLUDE_COUNT)) {
createdTag.setCount(Optional.ofNullable(tagsCountMap.get(createdTag.getTag())).orElse(0) + 1);
}
ret.add(createdTag);
}
return ret;
}
catch (IllegalArgumentException e)
{
throw new InvalidArgumentException(e.getMessage());
}
}
public void deleteTag(String nodeId, String tagId)
{
NodeRef nodeRef = nodes.validateNode(nodeId);
getTag(tagId);
NodeRef existingTagNodeRef = validateTag(tagId);
String tagValue = taggingService.getTagName(existingTagNodeRef);
taggingService.removeTag(nodeRef, tagValue);
}
@Override
public void deleteTagById(StoreRef storeRef, String tagId) {
verifyAdminAuthority();
NodeRef tagNodeRef = validateTag(storeRef, tagId);
String tagValue = taggingService.getTagName(tagNodeRef);
taggingService.deleteTag(storeRef, tagValue);
}
@Override
public CollectionWithPagingInfo<Tag> getTags(StoreRef storeRef, Parameters params)
{
Paging paging = params.getPaging();
PagingResults<Pair<NodeRef, String>> results = taggingService.getTags(storeRef, Util.getPagingRequest(paging));
taggingService.getPagedTags(storeRef, 0, paging.getMaxItems());
Map<Integer, Collection<String>> namesFilters = resolveTagNamesQuery(params.getQuery());
PagingResults<Pair<NodeRef, String>> results = taggingService.getTags(storeRef, Util.getPagingRequest(paging), namesFilters.get(EQUALS), namesFilters.get(MATCHES));
Integer totalItems = results.getTotalResultCount().getFirst();
List<Pair<NodeRef, String>> page = results.getPage();
List<Tag> tags = new ArrayList<Tag>(page.size());
List<Pair<String, Integer>> tagsByCount = null;
Map<String, Integer> tagsByCountMap = new HashMap<String, Integer>();
List<Tag> tags = new ArrayList<>(page.size());
for (Pair<NodeRef, String> pair : page)
{
Tag selectedTag = new Tag(pair.getFirst(), pair.getSecond());
tags.add(selectedTag);
}
if (params.getInclude().contains(PARAM_INCLUDE_COUNT))
{
tagsByCount = taggingService.findTaggedNodesAndCountByTagName(storeRef);
List<Pair<String, Integer>> tagsByCount = taggingService.findTaggedNodesAndCountByTagName(storeRef);
Map<String, Integer> tagsByCountMap = new HashMap<>();
if (tagsByCount != null)
{
for (Pair<String, Integer> tagByCountElem : tagsByCount)
@@ -149,86 +190,149 @@ public class TagsImpl implements Tags
tagsByCountMap.put(tagByCountElem.getFirst(), tagByCountElem.getSecond());
}
}
}
for (Pair<NodeRef, String> pair : page)
{
Tag selectedTag = new Tag(pair.getFirst(), pair.getSecond());
selectedTag.setCount(tagsByCountMap.get(selectedTag.getTag()));
tags.add(selectedTag);
tags.forEach(tag -> tag.setCount(Optional.ofNullable(tagsByCountMap.get(tag.getTag())).orElse(0)));
}
return CollectionWithPagingInfo.asPaged(paging, tags, results.hasMoreItems(), (totalItems == null ? null : totalItems.intValue()));
return CollectionWithPagingInfo.asPaged(paging, tags, results.hasMoreItems(), totalItems);
}
public NodeRef validateTag(String tagId)
{
NodeRef tagNodeRef = nodes.validateNode(tagId);
if(tagNodeRef == null)
{
throw new EntityNotFoundException(tagId);
}
return tagNodeRef;
}
public NodeRef validateTag(StoreRef storeRef, String tagId)
{
NodeRef tagNodeRef = nodes.validateNode(storeRef, tagId);
if(tagNodeRef == null)
{
throw new EntityNotFoundException(tagId);
}
return tagNodeRef;
}
public Tag changeTag(StoreRef storeRef, String tagId, Tag tag)
{
try
{
NodeRef existingTagNodeRef = validateTag(storeRef, tagId);
String existingTagName = taggingService.getTagName(existingTagNodeRef);
String newTagName = tag.getTag();
NodeRef newTagNodeRef = taggingService.changeTag(storeRef, existingTagName, newTagName);
return new Tag(newTagNodeRef, newTagName);
}
catch(NonExistentTagException e)
{
throw new NotFoundException(e.getMessage());
}
catch(TagExistsException e)
{
throw new ConstraintViolatedException(e.getMessage());
}
catch(TaggingException e)
{
throw new InvalidArgumentException(e.getMessage());
}
}
public Tag getTag(String tagId)
{
return getTag(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, tagId);
}
public Tag getTag(StoreRef storeRef, String tagId)
{
NodeRef tagNodeRef = validateTag(storeRef, tagId);
String tagValue = taggingService.getTagName(tagNodeRef);
return new Tag(tagNodeRef, tagValue);
}
public CollectionWithPagingInfo<Tag> getTags(String nodeId, Parameters params)
{
NodeRef nodeRef = validateTag(nodeId);
PagingResults<Pair<NodeRef, String>> results = taggingService.getTags(nodeRef, Util.getPagingRequest(params.getPaging()));
Integer totalItems = results.getTotalResultCount().getFirst();
List<Pair<NodeRef, String>> page = results.getPage();
List<Tag> tags = new ArrayList<Tag>(page.size());
for(Pair<NodeRef, String> pair : page)
{
tags.add(new Tag(pair.getFirst(), pair.getSecond()));
}
return CollectionWithPagingInfo.asPaged(params.getPaging(), tags, results.hasMoreItems(), (totalItems == null ? null : totalItems.intValue()));
}
}
public NodeRef validateTag(String tagId)
{
NodeRef tagNodeRef = nodes.validateNode(tagId);
return checkTagRootAsNodePrimaryParent(tagId, tagNodeRef);
}
public NodeRef validateTag(StoreRef storeRef, String tagId)
{
NodeRef tagNodeRef = nodes.validateNode(storeRef, tagId);
return checkTagRootAsNodePrimaryParent(tagId, tagNodeRef);
}
public Tag changeTag(StoreRef storeRef, String tagId, Tag tag)
{
try
{
NodeRef existingTagNodeRef = validateTag(storeRef, tagId);
String existingTagName = taggingService.getTagName(existingTagNodeRef);
String newTagName = tag.getTag();
NodeRef newTagNodeRef = taggingService.changeTag(storeRef, existingTagName, newTagName);
return new Tag(newTagNodeRef, newTagName);
}
catch(NonExistentTagException e)
{
throw new NotFoundException(e.getMessage());
}
catch(TagExistsException e)
{
throw new ConstraintViolatedException(e.getMessage());
}
catch(TaggingException e)
{
throw new InvalidArgumentException(e.getMessage());
}
}
public Tag getTag(String tagId)
{
return getTag(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, tagId);
}
public Tag getTag(StoreRef storeRef, String tagId)
{
NodeRef tagNodeRef = validateTag(storeRef, tagId);
String tagValue = taggingService.getTagName(tagNodeRef);
return new Tag(tagNodeRef, tagValue);
}
public CollectionWithPagingInfo<Tag> getTags(String nodeId, Parameters params)
{
NodeRef nodeRef = nodes.validateOrLookupNode(nodeId);
PagingResults<Pair<NodeRef, String>> results = taggingService.getTags(nodeRef, Util.getPagingRequest(params.getPaging()));
Integer totalItems = results.getTotalResultCount().getFirst();
List<Pair<NodeRef, String>> page = results.getPage();
List<Tag> tags = new ArrayList<>(page.size());
for(Pair<NodeRef, String> pair : page)
{
tags.add(new Tag(pair.getFirst(), pair.getSecond()));
}
return CollectionWithPagingInfo.asPaged(params.getPaging(), tags, results.hasMoreItems(), (totalItems == null ? null : totalItems.intValue()));
}
@Experimental
@Override
public List<Tag> createTags(final StoreRef storeRef, final List<Tag> tags, final Parameters parameters)
{
verifyAdminAuthority();
final List<String> tagNames = Optional.ofNullable(tags).orElse(Collections.emptyList()).stream()
.filter(Objects::nonNull)
.map(Tag::getTag)
.distinct()
.collect(toList());
if (CollectionUtils.isEmpty(tagNames))
{
throw new InvalidArgumentException(NOT_A_VALID_TAG);
}
return taggingService.createTags(storeRef, tagNames).stream()
.map(pair -> Tag.builder().tag(pair.getFirst()).nodeRef(pair.getSecond()).create())
.peek(tag -> {
if (parameters.getInclude().contains(PARAM_INCLUDE_COUNT))
{
tag.setCount(0);
}
}).collect(toList());
}
private void verifyAdminAuthority()
{
if (!authorityService.hasAdminAuthority())
{
throw new PermissionDeniedException(NO_PERMISSION_TO_MANAGE_A_TAG);
}
}
/**
* Method resolves where query looking for clauses: EQUALS, IN or MATCHES.
* Expected values for EQUALS and IN will be merged under EQUALS clause.
* @param namesQuery Where query with expected tag name(s).
* @return Map of expected exact and alike tag names.
*/
private Map<Integer, Collection<String>> resolveTagNamesQuery(final Query namesQuery)
{
if (namesQuery == null || namesQuery == QueryImpl.EMPTY)
{
return Collections.emptyMap();
}
final Map<Integer, Collection<String>> properties = QueryHelper
.resolve(namesQuery)
.usingOrOperator()
.withoutNegations()
.getProperty(PARAM_WHERE_TAG)
.getExpectedValuesForAnyOf(EQUALS, IN, MATCHES)
.skipNegated();
return properties.entrySet().stream()
.collect(Collectors.groupingBy((entry) -> {
if (entry.getKey() == EQUALS || entry.getKey() == IN)
{
return EQUALS;
}
else
{
return MATCHES;
}
}, Collectors.flatMapping((entry) -> entry.getValue().stream().map(String::toLowerCase), Collectors.toCollection(HashSet::new))));
}
private NodeRef checkTagRootAsNodePrimaryParent(String tagId, NodeRef tagNodeRef)
{
if ( tagNodeRef == null || !nodeService.getPrimaryParent(tagNodeRef).getParentRef().equals(tagParentNodeRef))
{
throw new EntityNotFoundException(tagId);
}
return tagNodeRef;
}
}

View File

@@ -134,7 +134,7 @@ public class RestRuleModelMapper implements RestModelMapper<Rule, org.alfresco.s
public org.alfresco.service.cmr.rule.Rule toServiceModel(Rule restRuleModel)
{
final org.alfresco.service.cmr.rule.Rule serviceRule = new org.alfresco.service.cmr.rule.Rule();
final NodeRef nodeRef = (restRuleModel.getId() != null) ? nodes.validateOrLookupNode(restRuleModel.getId(), null) : null;
final NodeRef nodeRef = (restRuleModel.getId() != null) ? nodes.validateOrLookupNode(restRuleModel.getId()) : null;
serviceRule.setNodeRef(nodeRef);
serviceRule.setTitle(restRuleModel.getName());
serviceRule.setDescription(restRuleModel.getDescription());

View File

@@ -129,7 +129,7 @@ public class RestRuleSimpleConditionModelMapper implements RestModelMapper<Simpl
parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_ASPECT, ContentModel.ASPECT_GEN_CLASSIFIABLE);
try
{
parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, nodes.validateOrLookupNode(parameter, null));
parameterValues.put(InCategoryEvaluator.PARAM_CATEGORY_VALUE, nodes.validateOrLookupNode(parameter));
} catch (EntityNotFoundException e) {
throw new InvalidArgumentException(CATEGORY_INVALID_MSG);
}

View File

@@ -173,7 +173,7 @@ public class ActionParameterConverter
}
else if (typeQName.isMatch(DataTypeDefinition.NODE_REF))
{
NodeRef nodeRef = nodes.validateOrLookupNode(stringValue, null);
NodeRef nodeRef = nodes.validateOrLookupNode(stringValue);
if (permissionService.hasReadPermission(nodeRef) != ALLOWED)
{
throw new EntityNotFoundException(stringValue);

View File

@@ -72,7 +72,7 @@ public class NodeValidator
{
try
{
final NodeRef nodeRef = nodes.validateOrLookupNode(folderNodeId, null);
final NodeRef nodeRef = nodes.validateOrLookupNode(folderNodeId);
validatePermission(requireChangePermission, nodeRef);
verifyNodeType(nodeRef, ContentModel.TYPE_FOLDER, null);

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -34,6 +34,7 @@ public class Category
private String name;
private String parentId;
private boolean hasChildren;
private Integer count;
public String getId()
{
@@ -45,6 +46,11 @@ public class Category
this.id = id;
}
public void setCategoryId(String categoryId)
{
this.id = categoryId;
}
public String getName()
{
return name;
@@ -75,20 +81,38 @@ public class Category
this.hasChildren = hasChildren;
}
public Integer getCount()
{
return count;
}
public void setCount(Integer count)
{
this.count = count;
}
@Override
public boolean equals(Object o)
{
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Category category = (Category) o;
return hasChildren == category.hasChildren && Objects.equals(id, category.id) && name.equals(category.name) &&
Objects.equals(parentId, category.parentId);
return hasChildren == category.hasChildren && Objects.equals(id, category.id) && Objects.equals(name, category.name) && Objects.equals(parentId, category.parentId)
&& Objects.equals(count, category.count);
}
@Override
public int hashCode()
{
return Objects.hash(id, name, parentId, hasChildren);
return Objects.hash(id, name, parentId, hasChildren, count);
}
@Override
public String toString()
{
return "Category{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", parentId='" + parentId + '\'' + ", hasChildren=" + hasChildren + ", count=" + count + '}';
}
public static Builder builder()
@@ -102,6 +126,7 @@ public class Category
private String name;
private String parentId;
private boolean hasChildren;
private Integer count;
public Builder id(String id)
{
@@ -127,6 +152,12 @@ public class Category
return this;
}
public Builder count(Integer count)
{
this.count = count;
return this;
}
public Category create()
{
final Category category = new Category();
@@ -134,6 +165,7 @@ public class Category
category.setName(name);
category.setParentId(parentId);
category.setHasChildren(hasChildren);
category.setCount(count);
return category;
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,6 +25,8 @@
*/
package org.alfresco.rest.api.model;
import java.util.Objects;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.alfresco.rest.framework.resource.UniqueId;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -99,42 +101,64 @@ public class Tag implements Comparable<Tag>
}
@Override
public int hashCode()
public boolean equals(Object o)
{
final int prime = 31;
int result = 1;
result = prime * result + ((nodeRef == null) ? 0 : nodeRef.hashCode());
return result;
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Tag tag1 = (Tag) o;
return Objects.equals(nodeRef, tag1.nodeRef) && Objects.equals(tag, tag1.tag) && Objects.equals(count, tag1.count);
}
/*
* Tags are equal if they have the same NodeRef
*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj)
public int hashCode()
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tag other = (Tag) obj;
if (nodeRef == null) {
if (other.nodeRef != null)
return false;
} else if (!nodeRef.equals(other.nodeRef))
return false;
return true;
return Objects.hash(nodeRef, tag, count);
}
@Override
public String toString()
{
return "Tag [nodeRef=" + nodeRef + ", tag=" + tag + "]";
return "Tag{" + "nodeRef=" + nodeRef + ", tag='" + tag + '\'' + ", count=" + count + '}';
}
public static Builder builder()
{
return new Builder();
}
public static class Builder
{
private NodeRef nodeRef;
private String tag;
private Integer count;
public Builder nodeRef(NodeRef nodeRef)
{
this.nodeRef = nodeRef;
return this;
}
public Builder tag(String tag)
{
this.tag = tag;
return this;
}
public Builder count(Integer count)
{
this.count = count;
return this;
}
public Tag create()
{
final Tag tag = new Tag();
tag.setNodeRef(nodeRef);
tag.setTag(this.tag);
tag.setCount(count);
return tag;
}
}
}

View File

@@ -31,13 +31,9 @@ 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.resource.parameters.SortColumn;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.util.ParameterCheck;
import java.util.List;
import java.util.stream.Collectors;
@RelationshipResource(name = "action-definitions", entityResource = NodesEntityResource.class, title = "Node action definitions")
public class NodeActionDefinitionsRelation extends AbstractNodeRelation
implements RelationshipResourceAction.Read<ActionDefinition>
@@ -59,7 +55,7 @@ public class NodeActionDefinitionsRelation extends AbstractNodeRelation
@Override
public CollectionWithPagingInfo<ActionDefinition> readAll(String entityResourceId, Parameters params)
{
NodeRef parentNodeRef = nodes.validateOrLookupNode(entityResourceId, null);
NodeRef parentNodeRef = nodes.validateOrLookupNode(entityResourceId);
return actions.getActionDefinitions(parentNodeRef, params);
}
}

View File

@@ -25,6 +25,11 @@
*/
package org.alfresco.rest.api.nodes;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.alfresco.rest.antlr.WhereClauseParser;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.Node;
@@ -41,11 +46,6 @@ import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QNamePattern;
import org.alfresco.service.namespace.RegexQNamePattern;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Node Parents
*
@@ -67,7 +67,7 @@ public class NodeParentsRelation extends AbstractNodeRelation implements Relatio
@WebApiDescription(title = "Return a list of parent nodes based on child assocs")
public CollectionWithPagingInfo<Node> readAll(String childNodeId, Parameters parameters)
{
NodeRef childNodeRef = nodes.validateOrLookupNode(childNodeId, null);
NodeRef childNodeRef = nodes.validateOrLookupNode(childNodeId);
QNamePattern assocTypeQNameParam = RegexQNamePattern.MATCH_ALL;

View File

@@ -25,6 +25,8 @@
*/
package org.alfresco.rest.api.nodes;
import java.util.List;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.AssocChild;
import org.alfresco.rest.api.model.Node;
@@ -41,8 +43,6 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.service.namespace.QNamePattern;
import org.alfresco.service.namespace.RegexQNamePattern;
import java.util.List;
/**
* Node Secondary Children
*
@@ -71,7 +71,7 @@ public class NodeSecondaryChildrenRelation extends AbstractNodeRelation implemen
@WebApiDescription(title = "Return a paged list of secondary child nodes based on child assocs")
public CollectionWithPagingInfo<Node> readAll(String parentNodeId, Parameters parameters)
{
NodeRef parentNodeRef = nodes.validateOrLookupNode(parentNodeId, null);
NodeRef parentNodeRef = nodes.validateOrLookupNode(parentNodeId);
QNamePattern assocTypeQNameParam = getAssocTypeFromWhereElseAll(parameters);

View File

@@ -25,6 +25,8 @@
*/
package org.alfresco.rest.api.nodes;
import java.util.List;
import org.alfresco.rest.api.model.Node;
import org.alfresco.rest.framework.WebApiDescription;
import org.alfresco.rest.framework.resource.RelationshipResource;
@@ -35,8 +37,6 @@ import org.alfresco.service.cmr.repository.AssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.namespace.QNamePattern;
import java.util.List;
/**
* Node Sources - list node (peer) associations from target to sources
*
@@ -54,7 +54,7 @@ public class NodeSourcesRelation extends AbstractNodeRelation implements Relatio
@WebApiDescription(title = "Return a paged list of sources nodes based on (peer) assocs")
public CollectionWithPagingInfo<Node> readAll(String targetNodeId, Parameters parameters)
{
NodeRef targetNodeRef = nodes.validateOrLookupNode(targetNodeId, null);
NodeRef targetNodeRef = nodes.validateOrLookupNode(targetNodeId);
QNamePattern assocTypeQNameParam = getAssocTypeFromWhereElseAll(parameters);

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.api.nodes;
import java.util.List;
@@ -61,7 +61,7 @@ public class NodeTagsRelation implements RelationshipResourceAction.Create<Tag>,
@WebApiDescription(title="Adds one or more tags to the node with id 'nodeId'.")
public List<Tag> create(String nodeId, List<Tag> tagsToCreate, Parameters parameters)
{
return tags.addTags(nodeId, tagsToCreate);
return tags.addTags(nodeId, tagsToCreate, parameters);
}
@Override

View File

@@ -25,6 +25,8 @@
*/
package org.alfresco.rest.api.nodes;
import java.util.List;
import org.alfresco.rest.api.Nodes;
import org.alfresco.rest.api.model.AssocTarget;
import org.alfresco.rest.api.model.Node;
@@ -40,8 +42,6 @@ import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.namespace.QNamePattern;
import org.alfresco.service.namespace.RegexQNamePattern;
import java.util.List;
/**
* Node Targets
*
@@ -64,7 +64,7 @@ public class NodeTargetsRelation extends AbstractNodeRelation implements
@WebApiDescription(title = "Return a paged list of target nodes based on (peer) assocs")
public CollectionWithPagingInfo<Node> readAll(String sourceNodeId, Parameters parameters)
{
NodeRef sourceNodeRef = nodes.validateOrLookupNode(sourceNodeId, null);
NodeRef sourceNodeRef = nodes.validateOrLookupNode(sourceNodeId);
QNamePattern assocTypeQNameParam = getAssocTypeFromWhereElseAll(parameters);

View File

@@ -25,6 +25,13 @@
*/
package org.alfresco.rest.api.nodes;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.directurl.DirectAccessUrlDisabledException;
import org.alfresco.repo.node.integrity.IntegrityException;
@@ -65,13 +72,6 @@ import org.alfresco.util.ParameterCheck;
import org.alfresco.util.PropertyCheck;
import org.springframework.beans.factory.InitializingBean;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Node Versions - version history
*
@@ -117,7 +117,7 @@ public class NodeVersionsRelation extends AbstractNodeRelation implements
@WebApiDescription(title = "Return version history as a paged list of version node infos")
public CollectionWithPagingInfo<Node> readAll(String nodeId, Parameters parameters)
{
NodeRef nodeRef = nodes.validateOrLookupNode(nodeId, null);
NodeRef nodeRef = nodes.validateOrLookupNode(nodeId);
VersionHistory vh = versionService.getVersionHistory(nodeRef);
@@ -293,7 +293,7 @@ public class NodeVersionsRelation extends AbstractNodeRelation implements
public Version findVersion(String nodeId, String versionLabelId)
{
NodeRef nodeRef = nodes.validateOrLookupNode(nodeId, null);
NodeRef nodeRef = nodes.validateOrLookupNode(nodeId);
VersionHistory vh = versionService.getVersionHistory(nodeRef);
if (vh != null)
{

View File

@@ -1,30 +1,33 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.rest.api.tags;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import org.alfresco.rest.api.Tags;
import org.alfresco.rest.api.model.Tag;
import org.alfresco.rest.framework.WebApiDescription;
@@ -33,12 +36,14 @@ import org.alfresco.rest.framework.resource.EntityResource;
import org.alfresco.rest.framework.resource.actions.interfaces.EntityResourceAction;
import org.alfresco.rest.framework.resource.parameters.CollectionWithPagingInfo;
import org.alfresco.rest.framework.resource.parameters.Parameters;
import org.alfresco.service.Experimental;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.util.ParameterCheck;
import org.springframework.beans.factory.InitializingBean;
@EntityResource(name="tags", title = "Tags")
public class TagsEntityResource implements EntityResourceAction.Read<Tag>, EntityResourceAction.ReadById<Tag>, EntityResourceAction.Update<Tag>, InitializingBean
public class TagsEntityResource implements EntityResourceAction.Read<Tag>,
EntityResourceAction.ReadById<Tag>, EntityResourceAction.Update<Tag>, EntityResourceAction.Create<Tag>, EntityResourceAction.Delete, InitializingBean
{
private Tags tags;
@@ -54,9 +59,8 @@ public class TagsEntityResource implements EntityResourceAction.Read<Tag>, Entit
}
/**
*
* Returns a paged list of all currently used tags in the store workspace://SpacesStore for the current tenant.
*
* GET /tags
*/
@Override
@WebApiDescription(title="A paged list of all tags in the network.")
@@ -77,4 +81,25 @@ public class TagsEntityResource implements EntityResourceAction.Read<Tag>, Entit
{
return tags.getTag(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id);
}
/**
* POST /tags
*/
@Experimental
@WebApiDescription(
title = "Create an orphan tag",
description = "Creates a tag, which is not associated with any node",
successStatus = HttpServletResponse.SC_CREATED
)
@Override
public List<Tag> create(List<Tag> tags, Parameters parameters)
{
return this.tags.createTags(tags, parameters);
}
@Override
public void delete(String id, Parameters parameters)
{
tags.deleteTagById(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id);
}
}

View File

@@ -0,0 +1,51 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2023 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.framework.core.exceptions;
/**
* Type of provided node is invalid.
*/
public class InvalidNodeTypeException extends ApiException
{
private static final long serialVersionUID = -672100019820298939L;
public static String DEFAULT_MESSAGE_ID = "framework.exception.InvalidNodeType";
public InvalidNodeTypeException(String msgId)
{
super(msgId);
}
public InvalidNodeTypeException(Object[] msgParams)
{
super(DEFAULT_MESSAGE_ID, msgParams);
}
public InvalidNodeTypeException(String msgId, Object[] msgParams)
{
super(msgId, msgParams);
}
}

View File

@@ -51,7 +51,6 @@ public interface SerializablePagedCollection<T>
/**
* Indicates the total number of items available.
*
* Can be greater than the number of items returned in the list.
*
*/

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -27,13 +27,11 @@
package org.alfresco.rest.framework.resource.parameters;
import org.alfresco.rest.api.search.context.SearchContext;
import org.alfresco.service.Experimental;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Experimental
public class ArrayListPage<E> extends ArrayList<E> implements ListPage<E>
{
private final Paging paging;

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2022 Alfresco Software Limited
* Copyright (C) 2005 - 2023 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -28,7 +28,6 @@ package org.alfresco.rest.framework.resource.parameters;
import org.alfresco.query.PagingResults;
import org.alfresco.rest.framework.resource.SerializablePagedCollection;
import org.alfresco.service.Experimental;
import org.alfresco.util.Pair;
import java.util.Collection;
@@ -38,10 +37,8 @@ import java.util.List;
/**
* List page with paging information.
*
*
* @param <E> - list element type
*/
@Experimental
public interface ListPage<E> extends List<E>, PagingResults<E>, SerializablePagedCollection<E>
{

View File

@@ -0,0 +1,259 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2023 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.framework.resource.parameters.where;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.alfresco.rest.antlr.WhereClauseParser;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
/**
* Basic implementation of {@link QueryHelper.WalkerCallbackAdapter} providing universal handling of Where query clauses.
* This implementation supports AND operator and all clause types.
* Be default, walker verifies strictly if expected or unexpected properties, and it's comparison types are present in query
* and throws {@link InvalidQueryException} if they are missing.
*/
public class BasicQueryWalker extends QueryHelper.WalkerCallbackAdapter
{
private static final String EQUALS_AND_IN_NOT_ALLOWED_TOGETHER = "Where query error: cannot use '=' (EQUALS) AND 'IN' clauses with same property: %s";
private static final String MISSING_PROPERTY = "Where query error: property with name: %s not present";
static final String MISSING_CLAUSE_TYPE = "Where query error: property with name: %s expects clause: %s";
static final String MISSING_ANY_CLAUSE_OF_TYPE = "Where query error: property with name: %s expects at least one of clauses: %s";
private static final String PROPERTY_NOT_EXPECTED = "Where query error: property with name: %s is not expected";
private static final String PROPERTY_NOT_NEGATABLE = "Where query error: property with name: %s cannot be negated";
private static final String PROPERTY_NAMES_EMPTY = "Cannot verify WHERE query without expected property names";
private Collection<String> expectedPropertyNames;
private final Map<String, WhereProperty> properties;
protected boolean clausesNegatable = true;
protected boolean validateStrictly = true;
public BasicQueryWalker()
{
this.properties = new HashMap<>();
}
public BasicQueryWalker(final String... expectedPropertyNames)
{
this();
this.expectedPropertyNames = Set.of(expectedPropertyNames);
}
public BasicQueryWalker(final Collection<String> expectedPropertyNames)
{
this();
this.expectedPropertyNames = expectedPropertyNames;
}
public void setClausesNegatable(final boolean clausesNegatable)
{
this.clausesNegatable = clausesNegatable;
}
public void setValidateStrictly(boolean validateStrictly)
{
this.validateStrictly = validateStrictly;
}
@Override
public void exists(String propertyName, boolean negated)
{
verifyPropertyExpectedness(propertyName);
verifyClausesNegatability(negated, propertyName);
addProperties(propertyName, WhereClauseParser.EXISTS, negated);
}
@Override
public void between(String propertyName, String firstValue, String secondValue, boolean negated)
{
verifyPropertyExpectedness(propertyName);
verifyClausesNegatability(negated, propertyName);
addProperties(propertyName, WhereClauseParser.BETWEEN, negated, firstValue, secondValue);
}
@Override
public void comparison(int type, String propertyName, String propertyValue, boolean negated)
{
verifyPropertyExpectedness(propertyName);
verifyClausesNegatability(negated, propertyName);
if (WhereClauseParser.EQUALS == type && isAndSupported() && containsProperty(propertyName, WhereClauseParser.IN, negated))
{
throw new InvalidQueryException(String.format(EQUALS_AND_IN_NOT_ALLOWED_TOGETHER, propertyName));
}
addProperties(propertyName, type, negated, propertyValue);
}
@Override
public void in(String propertyName, boolean negated, String... propertyValues)
{
verifyPropertyExpectedness(propertyName);
verifyClausesNegatability(negated, propertyName);
if (isAndSupported() && containsProperty(propertyName, WhereClauseParser.EQUALS, negated))
{
throw new InvalidQueryException(String.format(EQUALS_AND_IN_NOT_ALLOWED_TOGETHER, propertyName));
}
addProperties(propertyName, WhereClauseParser.IN, negated, propertyValues);
}
@Override
public void matches(final String propertyName, String propertyValue, boolean negated)
{
verifyPropertyExpectedness(propertyName);
verifyClausesNegatability(negated, propertyName);
addProperties(propertyName, WhereClauseParser.MATCHES, negated, propertyValue);
}
@Override
public void and()
{
// Don't need to do anything here - it's enough to enable AND operator.
// OR is not supported at the same time.
}
/**
* Verify if property is expected, if not throws {@link InvalidQueryException}.
*/
protected void verifyPropertyExpectedness(final String propertyName)
{
if (validateStrictly && CollectionUtils.isNotEmpty(expectedPropertyNames) && !this.expectedPropertyNames.contains(propertyName))
{
throw new InvalidQueryException(String.format(PROPERTY_NOT_EXPECTED, propertyName));
}
else if (validateStrictly && CollectionUtils.isEmpty(expectedPropertyNames))
{
throw new IllegalStateException(PROPERTY_NAMES_EMPTY);
}
}
/**
* Verify if clause negations are allowed, if not throws {@link InvalidQueryException}.
*/
protected void verifyClausesNegatability(final boolean negated, final String propertyName)
{
if (!clausesNegatable && negated)
{
throw new InvalidQueryException(String.format(PROPERTY_NOT_NEGATABLE, propertyName));
}
}
protected boolean isAndSupported()
{
try
{
and();
return true;
}
catch (InvalidQueryException ignore)
{
return false;
}
}
protected void addProperties(final String propertyName, final int clauseType, final String... propertyValues)
{
this.addProperties(propertyName, clauseType, false, propertyValues);
}
protected void addProperties(final String propertyName, final int clauseType, final boolean negated, final String... propertyValues)
{
final WhereProperty.ClauseType type = WhereProperty.ClauseType.of(clauseType, negated);
final Set<String> propertiesToAdd = Optional.ofNullable(propertyValues).map(Set::of).orElse(Collections.emptySet());
if (this.containsProperty(propertyName))
{
this.properties.get(propertyName).addValuesToType(type, propertiesToAdd);
}
else
{
this.properties.put(propertyName, new WhereProperty(propertyName, type, propertiesToAdd, validateStrictly));
}
}
protected boolean containsProperty(final String propertyName)
{
return this.properties.containsKey(propertyName);
}
protected boolean containsProperty(final String propertyName, final int clauseType, final boolean negated)
{
return this.properties.containsKey(propertyName) && this.properties.get(propertyName).containsType(clauseType, negated);
}
@Override
public Collection<String> getProperty(String propertyName, int type, boolean negated)
{
return this.getProperty(propertyName).getExpectedValuesFor(type, negated);
}
public WhereProperty getProperty(final String propertyName)
{
if (validateStrictly && !this.containsProperty(propertyName))
{
throw new InvalidQueryException(String.format(MISSING_PROPERTY, propertyName));
}
return this.properties.get(propertyName);
}
public List<WhereProperty> getProperties(final String... propertyNames)
{
return Arrays.stream(propertyNames)
.filter(StringUtils::isNotBlank)
.distinct()
.peek(propertyName -> {
if (validateStrictly && !this.containsProperty(propertyName))
{
throw new InvalidQueryException(String.format(MISSING_PROPERTY, propertyName));
}
})
.map(this.properties::get)
.collect(Collectors.toList());
}
public Map<String, WhereProperty> getPropertiesAsMap(final String... propertyNames)
{
return Arrays.stream(propertyNames)
.filter(StringUtils::isNotBlank)
.distinct()
.peek(propertyName -> {
if (validateStrictly && !this.containsProperty(propertyName))
{
throw new InvalidQueryException(String.format(MISSING_PROPERTY, propertyName));
}
})
.collect(Collectors.toMap(propertyName -> propertyName, this.properties::get));
}
}

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