mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-11-12 15:39:46 +00:00
Compare commits
4 Commits
21.1
...
feature/AC
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc32451c28 | ||
|
|
4e354449ab | ||
|
|
902fe505fa | ||
|
|
14e21eb62d |
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@@ -23,7 +23,6 @@ env:
|
||||
MAVEN_USERNAME: ${{ secrets.NEXUS_USERNAME }}
|
||||
QUAY_PASSWORD: ${{ secrets.QUAY_PASSWORD }}
|
||||
QUAY_USERNAME: ${{ secrets.QUAY_USERNAME }}
|
||||
CI_WORKSPACE: ${{ github.workspace }}
|
||||
TAS_ENVIRONMENT: ./packaging/tests/environment
|
||||
TAS_SCRIPTS: ../alfresco-community-repo/packaging/tests/scripts
|
||||
|
||||
@@ -317,8 +316,7 @@ jobs:
|
||||
- testSuite: MTLSTestSuite
|
||||
compose-profile: with-mtls-transform-core-aio
|
||||
mtls: true
|
||||
disabledHostnameVerification: false
|
||||
mvn-options: '-Dencryption.ssl.keystore.location=${CI_WORKSPACE}/keystores/alfresco/alfresco.keystore -Dencryption.ssl.truststore.location=${CI_WORKSPACE}/keystores/alfresco/alfresco.truststore'
|
||||
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
|
||||
@@ -330,14 +328,8 @@ jobs:
|
||||
- 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"
|
||||
if ${{ matrix.disabledHostnameVerification }} ; then
|
||||
bash ${{ env.CI_WORKSPACE }}/alfresco-ssl-generator/scripts/ci/generate_keystores_wrong_hostnames.sh
|
||||
echo "HOSTNAME_VERIFICATION_DISABLED=true" >> "$GITHUB_ENV"
|
||||
else
|
||||
bash ${{ env.CI_WORKSPACE }}/alfresco-ssl-generator/scripts/ci/generate_keystores.sh
|
||||
echo "HOSTNAME_VERIFICATION_DISABLED=false" >> "$GITHUB_ENV"
|
||||
fi
|
||||
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
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
SOLR6_TAG=2.0.7-A5
|
||||
SOLR6_TAG=2.0.7-A2
|
||||
POSTGRES_TAG=14.4
|
||||
ACTIVEMQ_TAG=5.17.1-jre11-rockylinux8
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Version label
|
||||
version.major=7
|
||||
version.minor=4
|
||||
version.revision=1
|
||||
version.revision=0
|
||||
version.label=
|
||||
|
||||
# Edition label
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -38,7 +38,9 @@ tags:
|
||||
description: Retrieve and manage unfiled records containers
|
||||
- name: unfiled-record-folders
|
||||
description: Retrieve and manage unfiled record folders
|
||||
|
||||
- name: events
|
||||
description: Retrieve and manage retention events
|
||||
|
||||
paths:
|
||||
## GS sites
|
||||
'/gs-sites':
|
||||
@@ -2092,8 +2094,172 @@ paths:
|
||||
description: Unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
'/events':
|
||||
get:
|
||||
tags:
|
||||
- events
|
||||
summary: List all available retention events
|
||||
description: |
|
||||
Gets the list of events that can be used by retention steps
|
||||
operationId: getAllEvents
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- $ref: '#/parameters/skipCountParam'
|
||||
- $ref: '#/parameters/maxItemsParam'
|
||||
responses:
|
||||
'200':
|
||||
description: Successful response
|
||||
schema:
|
||||
$ref: '#/definitions/EventPaging'
|
||||
'400':
|
||||
description: |
|
||||
Invalid parameter: value of **maxItems** or **skipCount** is invalid
|
||||
'401':
|
||||
description: Authentication failed
|
||||
default:
|
||||
description: Unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
|
||||
post:
|
||||
tags:
|
||||
- events
|
||||
summary: Create a new retention event
|
||||
description: |
|
||||
Creates a new event that can be used by retention schedules.
|
||||
operationId: createEvent
|
||||
parameters:
|
||||
- in: body
|
||||
name: eventBodyCreate
|
||||
description: The new event.
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/EventBody'
|
||||
consumes:
|
||||
- application/json
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
'201':
|
||||
description: Successful response
|
||||
schema:
|
||||
$ref: '#/definitions/EventEntry'
|
||||
'400':
|
||||
description: |
|
||||
Invalid parameter: **name** or **type** is invalid
|
||||
'401':
|
||||
description: Authentication failed
|
||||
'403':
|
||||
description: Current user does not have permission to create event
|
||||
'409':
|
||||
description: Cannot create event. An event with the name **name** already exists
|
||||
default:
|
||||
description: Unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
|
||||
'/events/{eventId}':
|
||||
get:
|
||||
tags:
|
||||
- events
|
||||
summary: Return event for given eventId
|
||||
description: |
|
||||
Gets information about the retention event with id **eventId**.
|
||||
operationId: getEvent
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- $ref: '#/parameters/eventIdParam'
|
||||
responses:
|
||||
'200':
|
||||
description: Successful response
|
||||
schema:
|
||||
$ref: '#/definitions/EventEntry'
|
||||
'400':
|
||||
description: |
|
||||
Invalid parameter: **eventId** is invalid
|
||||
'401':
|
||||
description: Authentication failed
|
||||
'404':
|
||||
description: "**eventId** does not exist"
|
||||
default:
|
||||
description: Unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
put:
|
||||
tags:
|
||||
- events
|
||||
summary: Update event for given eventId
|
||||
operationId: updateEvent
|
||||
description: |
|
||||
Updates retention event with id **eventId**.
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- $ref: '#/parameters/eventIdParam'
|
||||
- in: body
|
||||
name: eventBodyUpdate
|
||||
description: The event information to update.
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/EventBody'
|
||||
responses:
|
||||
'200':
|
||||
description: Successful response
|
||||
schema:
|
||||
$ref: '#/definitions/EventEntry'
|
||||
'400':
|
||||
description: |
|
||||
Invalid parameter: The update request is invalid or **eventId** is not a valid format or **eventBodyUpdate** is invalid
|
||||
'401':
|
||||
description: Authentication failed
|
||||
'403':
|
||||
description: Current user does not have permission to update events
|
||||
'404':
|
||||
description: "**eventId** does not exist"
|
||||
'409':
|
||||
description: Cannot update event. An event with the name **name** already exists
|
||||
default:
|
||||
description: Unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
|
||||
'/event-types':
|
||||
get:
|
||||
tags:
|
||||
- events
|
||||
summary: List all the retention event types
|
||||
description: |
|
||||
Gets a list of all the retention event types.
|
||||
operationId: getAllEventTypes
|
||||
produces:
|
||||
- application/json
|
||||
parameters:
|
||||
- $ref: '#/parameters/skipCountParam'
|
||||
- $ref: '#/parameters/maxItemsParam'
|
||||
responses:
|
||||
'200':
|
||||
description: Successful response
|
||||
schema:
|
||||
$ref: '#/definitions/EventTypePaging'
|
||||
'400':
|
||||
description: |
|
||||
Invalid parameter: value of **maxItems** or **skipCount** is invalid
|
||||
'401':
|
||||
description: Authentication failed
|
||||
default:
|
||||
description: Unexpected error
|
||||
schema:
|
||||
$ref: '#/definitions/Error'
|
||||
parameters:
|
||||
## event
|
||||
eventIdParam:
|
||||
name: eventId
|
||||
in: path
|
||||
description: The identifier of an event.
|
||||
required: true
|
||||
type: string
|
||||
## File plans
|
||||
filePlanEntryIncludeParam:
|
||||
name: include
|
||||
@@ -3761,4 +3927,92 @@ definitions:
|
||||
- SiteConsumer
|
||||
- SiteCollaborator
|
||||
- SiteContributor
|
||||
- SiteManager
|
||||
- SiteManager
|
||||
EventPaging:
|
||||
type: object
|
||||
properties:
|
||||
list:
|
||||
type: object
|
||||
properties:
|
||||
pagination:
|
||||
$ref: '#/definitions/Pagination'
|
||||
entries:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/EventEntry'
|
||||
EventEntry:
|
||||
type: object
|
||||
required:
|
||||
- entry
|
||||
properties:
|
||||
entry:
|
||||
$ref: '#/definitions/Event'
|
||||
Event:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
- type
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: this is the id of the event
|
||||
name:
|
||||
type: string
|
||||
description: This is the unique display label of the event
|
||||
type:
|
||||
type: string
|
||||
description: this is event type
|
||||
EventBody:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: This is the unique display label of the event
|
||||
type:
|
||||
type: string
|
||||
description: this is event type
|
||||
default: Simple
|
||||
EventTypePaging:
|
||||
type: object
|
||||
properties:
|
||||
list:
|
||||
type: object
|
||||
properties:
|
||||
pagination:
|
||||
$ref: '#/definitions/Pagination'
|
||||
entries:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/EventTypeEntry'
|
||||
EventTypeEntry:
|
||||
type: object
|
||||
required:
|
||||
- entry
|
||||
properties:
|
||||
entry:
|
||||
$ref: '#/definitions/EventType'
|
||||
EventType:
|
||||
type: object
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: this is the event type id
|
||||
name:
|
||||
type: string
|
||||
description: this is event type name
|
||||
isAutomatic:
|
||||
type: boolean
|
||||
description: Whether events of this type need completing manually or can be completed automatically
|
||||
default: true
|
||||
associationName:
|
||||
type: string
|
||||
description: The association used to determine whether automatic events of this type are complete
|
||||
actionOnAssociatedNode:
|
||||
type: string
|
||||
description: If an association name is set for this event type then it is possible to require an action to be completed on the associated node
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
</project>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
SOLR6_TAG=2.0.7-A5
|
||||
SOLR6_TAG=2.0.7-A2
|
||||
POSTGRES_TAG=14.4
|
||||
ACTIVEMQ_TAG=5.17.1-jre11-rockylinux8
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<organization>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -52,11 +52,6 @@ This must be unique within the parent category.
|
||||
*/
|
||||
private long count;
|
||||
|
||||
/**
|
||||
The path to this category.
|
||||
*/
|
||||
private String path;
|
||||
|
||||
public String getId()
|
||||
{
|
||||
return this.id;
|
||||
@@ -107,14 +102,6 @@ This must be unique within the parent category.
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
@@ -139,7 +126,6 @@ This must be unique within the parent category.
|
||||
", parentId='" + parentId + '\'' +
|
||||
", hasChildren=" + hasChildren +
|
||||
", count=" + count +
|
||||
", path=" + path +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,223 +0,0 @@
|
||||
/*
|
||||
* #%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.RestCategoryLinkBodyModel;
|
||||
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 CategoriesPathTests extends CategoriesRestTest
|
||||
{
|
||||
private FileModel file;
|
||||
private RestCategoryModel category;
|
||||
|
||||
@BeforeClass(alwaysRun = true)
|
||||
@Override
|
||||
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 a category");
|
||||
FolderModel folder = dataContent.usingUser(user).usingSite(site).createFolder();
|
||||
file = dataContent.usingUser(user).usingResource(folder).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
|
||||
category = prepareCategoryUnderRoot();
|
||||
|
||||
STEP("Wait for indexing to complete");
|
||||
Utility.sleep(1000, 60000, () -> restClient.authenticateUser(user)
|
||||
.withCoreAPI()
|
||||
.usingCategory(category)
|
||||
.include(INCLUDE_PATH_PARAM)
|
||||
.getCategory()
|
||||
.assertThat()
|
||||
.field(FIELD_PATH)
|
||||
.isNotNull());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify path for a category got by ID.
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API })
|
||||
public void testGetCategoryById_includePath()
|
||||
{
|
||||
STEP("Get category and verify if path is a general path for categories");
|
||||
final RestCategoryModel actualCategory = restClient.authenticateUser(user)
|
||||
.withCoreAPI()
|
||||
.usingCategory(category)
|
||||
.include(INCLUDE_PATH_PARAM)
|
||||
.getCategory();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
actualCategory.assertThat().field(FIELD_ID).is(category.getId());
|
||||
actualCategory.assertThat().field(FIELD_PATH).is("/categories/General");
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify path for category.
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API })
|
||||
public void testGetCategories_includePath()
|
||||
{
|
||||
STEP("Get few categories and verify its paths");
|
||||
final RestCategoryModel parentCategory = createCategoryModelWithId(ROOT_CATEGORY_ID);
|
||||
final RestCategoryModelsCollection actualCategories = restClient.authenticateUser(user)
|
||||
.withCoreAPI()
|
||||
.usingCategory(parentCategory)
|
||||
.include(INCLUDE_PATH_PARAM)
|
||||
.getCategoryChildren();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
assertTrue(actualCategories.getEntries().stream()
|
||||
.map(RestCategoryModel::onModel)
|
||||
.allMatch(cat -> cat.getPath().equals("/categories/General")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify path for child category.
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API })
|
||||
public void testGetChildCategory_includePath()
|
||||
{
|
||||
STEP("Create parent and child categories");
|
||||
final RestCategoryModel parentCategory = prepareCategoryUnderRoot();
|
||||
final RestCategoryModel childCategory = prepareCategoryUnder(parentCategory);
|
||||
|
||||
STEP("Verify path for created child categories");
|
||||
final RestCategoryModelsCollection actualCategories = restClient.authenticateUser(user)
|
||||
.withCoreAPI()
|
||||
.usingCategory(parentCategory)
|
||||
.include(INCLUDE_PATH_PARAM)
|
||||
.getCategoryChildren();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
actualCategories.getEntries().stream()
|
||||
.map(RestCategoryModel::onModel)
|
||||
.forEach(cat -> cat.assertThat().field(FIELD_PATH).is("/categories/General/" + parentCategory.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create category and verify that it has a path.
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API })
|
||||
public void testCreateCategory_includingPath()
|
||||
{
|
||||
STEP("Create a category under root and verify if path is a general path for categories");
|
||||
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_PATH_PARAM)
|
||||
.usingCategory(rootCategory)
|
||||
.createSingleCategory(aCategory);
|
||||
|
||||
restClient.assertStatusCodeIs(CREATED);
|
||||
createdCategory.assertThat().field(FIELD_NAME).is(categoryName);
|
||||
createdCategory.assertThat().field(FIELD_PATH).is("/categories/General");
|
||||
}
|
||||
|
||||
/**
|
||||
* Update category and verify that it has a path.
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API })
|
||||
public void testUpdateCategory_includePath()
|
||||
{
|
||||
STEP("Update linked category and verify if path is a general path for categories");
|
||||
final String categoryNewName = getRandomName("NewCategoryName");
|
||||
final RestCategoryModel fixedCategoryModel = createCategoryModelWithName(categoryNewName);
|
||||
final RestCategoryModel updatedCategory = restClient.authenticateUser(dataUser.getAdminUser())
|
||||
.withCoreAPI()
|
||||
.usingCategory(category)
|
||||
.include(INCLUDE_PATH_PARAM)
|
||||
.updateCategory(fixedCategoryModel);
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
updatedCategory.assertThat().field(FIELD_ID).is(category.getId());
|
||||
updatedCategory.assertThat().field(FIELD_PATH).is("/categories/General");
|
||||
}
|
||||
|
||||
/**
|
||||
* Link node to categories and verify that they have path.
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API })
|
||||
public void testLinkNodeToCategories_includePath()
|
||||
{
|
||||
STEP("Link node to categories and verify if path is a general path");
|
||||
final RestCategoryLinkBodyModel categoryLinkModel = createCategoryLinkModelWithId(category.getId());
|
||||
final RestCategoryModel linkedCategory = restClient.authenticateUser(dataUser.getAdminUser())
|
||||
.withCoreAPI()
|
||||
.usingNode(file)
|
||||
.include(INCLUDE_PATH_PARAM)
|
||||
.linkToCategory(categoryLinkModel);
|
||||
|
||||
restClient.assertStatusCodeIs(CREATED);
|
||||
linkedCategory.assertThat().field(FIELD_ID).is(category.getId());
|
||||
linkedCategory.assertThat().field(FIELD_PATH).is("/categories/General");
|
||||
}
|
||||
|
||||
/**
|
||||
* List categories for given node and verify that they have a path.
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API })
|
||||
public void testListCategoriesForNode_includePath()
|
||||
{
|
||||
STEP("Link file to category");
|
||||
final RestCategoryLinkBodyModel categoryLink = createCategoryLinkModelWithId(category.getId());
|
||||
final RestCategoryModel linkedCategory = restClient.authenticateUser(dataUser.getAdminUser())
|
||||
.withCoreAPI()
|
||||
.usingNode(file)
|
||||
.include(INCLUDE_PATH_PARAM)
|
||||
.linkToCategory(categoryLink);
|
||||
|
||||
STEP("Get linked category and verify if path is a general path");
|
||||
final RestCategoryModelsCollection linkedCategories = restClient.authenticateUser(dataUser.getAdminUser())
|
||||
.withCoreAPI()
|
||||
.usingNode(file)
|
||||
.include(INCLUDE_PATH_PARAM)
|
||||
.getLinkedCategories();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
linkedCategories.assertThat().entriesListCountIs(1);
|
||||
linkedCategories.getEntries().get(0).onModel().assertThat().field(FIELD_ID).is(category.getId());
|
||||
linkedCategories.getEntries().get(0).onModel().assertThat().field(FIELD_PATH).is("/categories/General");
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,6 @@ import org.testng.annotations.BeforeClass;
|
||||
abstract class CategoriesRestTest extends RestTest
|
||||
{
|
||||
protected static final String INCLUDE_COUNT_PARAM = "count";
|
||||
protected static final String INCLUDE_PATH_PARAM = "path";
|
||||
protected static final String ROOT_CATEGORY_ID = "-root-";
|
||||
protected static final String CATEGORY_NAME_PREFIX = "CategoryName";
|
||||
protected static final String FIELD_NAME = "name";
|
||||
@@ -54,7 +53,6 @@ abstract class CategoriesRestTest extends RestTest
|
||||
protected static final String FIELD_PARENT_ID = "parentId";
|
||||
protected static final String FIELD_HAS_CHILDREN = "hasChildren";
|
||||
protected static final String FIELD_COUNT = "count";
|
||||
protected static final String FIELD_PATH = "path";
|
||||
|
||||
protected UserModel user;
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ public class GetTagTests extends TagsDataPrep
|
||||
|
||||
@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()
|
||||
public void adminIsAbleToGetTag() throws Exception
|
||||
{
|
||||
RestTagModel returnedTag = restClient.authenticateUser(adminUserModel).withCoreAPI().getTag(documentTag);
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
@@ -35,7 +35,7 @@ public class GetTagTests extends TagsDataPrep
|
||||
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.SANITY, description = "Verify user with Manager role gets tag using REST API and status code is OK (200)")
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.SANITY })
|
||||
public void userWithManagerRoleIsAbleToGetTag()
|
||||
public void userWithManagerRoleIsAbleToGetTag() throws Exception
|
||||
{
|
||||
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager));
|
||||
|
||||
@@ -47,7 +47,7 @@ public class GetTagTests extends TagsDataPrep
|
||||
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION, description = "Verify user with Collaborator role gets tag using REST API and status code is OK (200)")
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void userWithCollaboratorRoleIsAbleToGetTag()
|
||||
public void userWithCollaboratorRoleIsAbleToGetTag() throws Exception
|
||||
{
|
||||
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteCollaborator));
|
||||
RestTagModel returnedTag = restClient.withCoreAPI().getTag(documentTag);
|
||||
@@ -57,7 +57,7 @@ public class GetTagTests extends TagsDataPrep
|
||||
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION, description = "Verify user with Contributor role gets tag using REST API and status code is OK (200)")
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void userWithContributorRoleIsAbleToGetTag()
|
||||
public void userWithContributorRoleIsAbleToGetTag() throws Exception
|
||||
{
|
||||
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteContributor));
|
||||
RestTagModel returnedTag = restClient.withCoreAPI().getTag(documentTag);
|
||||
@@ -67,7 +67,7 @@ public class GetTagTests extends TagsDataPrep
|
||||
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION, description = "Verify user with Consumer role gets tag using REST API and status code is OK (200)")
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void userWithConsumerRoleIsAbleToGetTag()
|
||||
public void userWithConsumerRoleIsAbleToGetTag() throws Exception
|
||||
{
|
||||
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteConsumer));
|
||||
RestTagModel returnedTag = restClient.withCoreAPI().getTag(documentTag);
|
||||
@@ -78,7 +78,7 @@ public class GetTagTests extends TagsDataPrep
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.SANITY, description = "Verify Manager user gets status code 401 if authentication call fails")
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.SANITY })
|
||||
// @Bug(id="MNT-16904", description = "It fails only on environment with tenants")
|
||||
public void managerIsNotAbleToGetTagIfAuthenticationFails()
|
||||
public void managerIsNotAbleToGetTagIfAuthenticationFails() throws Exception
|
||||
{
|
||||
UserModel managerUser = dataUser.usingAdmin().createRandomTestUser();
|
||||
String managerPassword = managerUser.getPassword();
|
||||
@@ -92,7 +92,7 @@ public class GetTagTests extends TagsDataPrep
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
|
||||
description = "Verify that if tag id is invalid status code returned is 400")
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void invalidTagIdTest()
|
||||
public void invalidTagIdTest() throws Exception
|
||||
{
|
||||
String tagId = documentTag.getId();
|
||||
documentTag.setId("random_tag_value");
|
||||
@@ -104,7 +104,7 @@ public class GetTagTests extends TagsDataPrep
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS },
|
||||
executionType = ExecutionType.REGRESSION, description = "Check that properties filter is applied when getting tag using Manager user.")
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void checkPropertiesFilterIsApplied()
|
||||
public void checkPropertiesFilterIsApplied() throws Exception
|
||||
{
|
||||
RestTagModel returnedTag = restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager))
|
||||
.withParams("properties=id,tag").withCoreAPI().getTag(documentTag);
|
||||
@@ -117,7 +117,7 @@ public class GetTagTests extends TagsDataPrep
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS },
|
||||
executionType = ExecutionType.REGRESSION, description = "Check that Manager user can get tag of a folder.")
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void getTagOfAFolder()
|
||||
public void getTagOfAFolder() throws Exception
|
||||
{
|
||||
RestTagModel returnedTag = restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager))
|
||||
.withCoreAPI().getTag(folderTag);
|
||||
@@ -128,7 +128,7 @@ public class GetTagTests extends TagsDataPrep
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS },
|
||||
executionType = ExecutionType.REGRESSION, description = "Check default error model schema. Use invalid skipCount parameter.")
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void checkDefaultErrorModelSchema()
|
||||
public void checkDefaultErrorModelSchema() throws Exception
|
||||
{
|
||||
restClient.authenticateUser(usersWithRoles.getOneUserWithRole(UserRole.SiteManager))
|
||||
.withParams("skipCount=abc").withCoreAPI().getTag(documentTag);
|
||||
@@ -140,14 +140,13 @@ public class GetTagTests extends TagsDataPrep
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that count field is not present for searched tag when not requested.
|
||||
* 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");
|
||||
String tagName = getRandomName(TAG_NAME_PREFIX).toLowerCase();
|
||||
final RestTagModel tagModel = createTagModelWithName(tagName);
|
||||
final RestTagModel tagModel = createTagModelWithName(getRandomName(TAG_NAME_PREFIX).toLowerCase());
|
||||
final RestTagModel createdTag = restClient.authenticateUser(adminUserModel).withCoreAPI().createSingleTag(tagModel);
|
||||
|
||||
restClient.assertStatusCodeIs(CREATED);
|
||||
@@ -156,26 +155,8 @@ public class GetTagTests extends TagsDataPrep
|
||||
final RestTagModel searchedTag = restClient.withCoreAPI().getTag(createdTag);
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
RestTagModel expected = RestTagModel.builder().id(createdTag.getId()).tag(tagName).create();
|
||||
searchedTag.assertThat().isEqualTo(expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the count field can be included.
|
||||
*/
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void testGetTag_includeCount()
|
||||
{
|
||||
STEP("Create unused tag as admin");
|
||||
String tagName = getRandomName(TAG_NAME_PREFIX).toLowerCase();
|
||||
RestTagModel tagModel = createTagModelWithName(tagName);
|
||||
RestTagModel createdTag = restClient.authenticateUser(adminUserModel).withCoreAPI().createSingleTag(tagModel);
|
||||
|
||||
STEP("Get a single tag with the count field");
|
||||
RestTagModel searchedTag = restClient.withCoreAPI().include("count").getTag(createdTag);
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
RestTagModel expected = RestTagModel.builder().id(createdTag.getId()).tag(tagName).count(0).create();
|
||||
searchedTag.assertThat().isEqualTo(expected);
|
||||
searchedTag.assertThat().field(FIELD_TAG).is(tagModel.getTag())
|
||||
.assertThat().field(FIELD_ID).isNotEmpty()
|
||||
.assertThat().field(FIELD_COUNT).isNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ 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.OK;
|
||||
|
||||
import java.util.Set;
|
||||
@@ -17,11 +16,6 @@ import org.alfresco.utility.testrail.annotation.TestRail;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static org.alfresco.utility.report.log.Step.STEP;
|
||||
|
||||
@Test(groups = {TestGroup.REQUIRE_SOLR})
|
||||
public class GetTagsTests extends TagsDataPrep
|
||||
{
|
||||
@@ -78,138 +72,6 @@ public class GetTagsTests extends TagsDataPrep
|
||||
.and().entriesListContains("tag", documentTagValue2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include count in the query parameters and ensure count is as expected for returned tags.
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void testGetTags_withIncludeCount()
|
||||
{
|
||||
STEP("Get tags including count filter and ensure count is as expected for returned tags");
|
||||
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||
.withParams("include=count")
|
||||
.withCoreAPI()
|
||||
.getTags();
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
|
||||
returnedCollection.getEntries().stream()
|
||||
.filter(e -> e.onModel().getTag().equals(folderTagValue) || e.onModel().getTag().equals(documentTagValue))
|
||||
.forEach(e -> e.onModel().assertThat().field("count").is(2));
|
||||
|
||||
returnedCollection.getEntries().stream()
|
||||
.filter(e -> e.onModel().getTag().equals(documentTagValue2))
|
||||
.forEach(e -> e.onModel().assertThat().field("count").is(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tags and order results by count. Default sort order should be ascending
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void testGetTags_withOrderByCountDefaultOrderShouldBeAsc()
|
||||
{
|
||||
STEP("Get tags and order results by count. Default sort order should be ascending");
|
||||
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||
.withParams("include=count&orderBy=count")
|
||||
.withCoreAPI()
|
||||
.getTags();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
returnedCollection.assertThat().entriesListIsSortedAscBy("count");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tags and order results by count in ascending order
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void testGetTags_withOrderByCountAsc()
|
||||
{
|
||||
STEP("Get tags and order results by count in ascending order");
|
||||
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||
.withParams("include=count&orderBy=count ASC")
|
||||
.withCoreAPI()
|
||||
.getTags();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
returnedCollection.assertThat().entriesListIsSortedAscBy("count");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tags and order results by count in descending order
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void testGetTags_withOrderByCountDesc()
|
||||
{
|
||||
STEP("Get tags and order results by count in descending order");
|
||||
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||
.withParams("include=count&orderBy=count DESC")
|
||||
.withCoreAPI()
|
||||
.getTags();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
returnedCollection.assertThat().entriesListIsSortedDescBy("count");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tags and order results by tag name. Default sort order should be ascending
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void testGetTags_withOrderByTagDefaultOrderShouldBeAsc()
|
||||
{
|
||||
STEP("Get tags and order results by tag name. Default sort order should be ascending");
|
||||
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||
.withParams("orderBy=tag")
|
||||
.withCoreAPI()
|
||||
.getTags();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
returnedCollection.assertThat().entriesListIsSortedAscBy("tag");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tags and order results by tag name in ascending order
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void testGetTags_withOrderByTagAsc()
|
||||
{
|
||||
STEP("Get tags and order results by tag name in ascending order");
|
||||
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||
.withParams("orderBy=tag ASC")
|
||||
.withCoreAPI()
|
||||
.getTags();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
returnedCollection.assertThat().entriesListIsSortedAscBy("tag");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tags and order results by tag name in descending order
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void testGetTags_withOrderByTagDesc()
|
||||
{
|
||||
STEP("Get tags and order results by tag name in descending order");
|
||||
returnedCollection = restClient.authenticateUser(adminUserModel)
|
||||
.withParams("orderBy=tag DESC")
|
||||
.withCoreAPI()
|
||||
.getTags();
|
||||
|
||||
restClient.assertStatusCodeIs(OK);
|
||||
returnedCollection.assertThat().entriesListIsSortedDescBy("tag");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that we get a 400 error when we request to order by count without also including the tag count.
|
||||
*/
|
||||
@Test(groups = { TestGroup.REST_API, TestGroup.TAGS, TestGroup.REGRESSION })
|
||||
public void testGetTags_orderByCountWithoutIncludeCount()
|
||||
{
|
||||
restClient.authenticateUser(adminUserModel)
|
||||
.withParams("orderBy=count")
|
||||
.withCoreAPI()
|
||||
.getTags();
|
||||
|
||||
restClient.assertStatusCodeIs(BAD_REQUEST);
|
||||
}
|
||||
|
||||
@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")
|
||||
@@ -331,7 +193,8 @@ public class GetTagsTests extends TagsDataPrep
|
||||
.getPagination().assertThat().field("maxItems").is(100)
|
||||
.and().field("hasMoreItems").is("false")
|
||||
.and().field("count").is("0")
|
||||
.and().field("skipCount").is(20000);
|
||||
.and().field("skipCount").is(20000)
|
||||
.and().field("totalItems").is(0);
|
||||
}
|
||||
|
||||
@TestRail(section = { TestGroup.REST_API, TestGroup.TAGS }, executionType = ExecutionType.REGRESSION,
|
||||
|
||||
@@ -22,8 +22,7 @@ public class TagsDataPrep extends RestTest
|
||||
protected static ListUserWithRoles usersWithRoles;
|
||||
protected static SiteModel siteModel;
|
||||
protected static FileModel document;
|
||||
protected static FolderModel folder, folder2;
|
||||
protected static RestTagModelsCollection folder2tags;
|
||||
protected static FolderModel folder;
|
||||
protected static String documentTagValue, documentTagValue2, folderTagValue;
|
||||
protected static RestTagModel documentTag, documentTag2, folderTag, orphanTag, returnedModel;
|
||||
protected static RestTagModelsCollection returnedCollection;
|
||||
@@ -39,7 +38,6 @@ public class TagsDataPrep extends RestTest
|
||||
usersWithRoles = dataUser.usingAdmin().addUsersWithRolesToSite(siteModel, UserRole.SiteManager, UserRole.SiteCollaborator, UserRole.SiteConsumer, UserRole.SiteContributor);
|
||||
document = dataContent.usingUser(adminUserModel).usingSite(siteModel).createContent(CMISUtil.DocumentType.TEXT_PLAIN);
|
||||
folder = dataContent.usingUser(adminUserModel).usingSite(siteModel).createFolder();
|
||||
folder2 = dataContent.usingUser(adminUserModel).usingSite(siteModel).createFolder();
|
||||
|
||||
documentTagValue = RandomData.getRandomName("tag").toLowerCase();
|
||||
documentTagValue2 = RandomData.getRandomName("tag").toLowerCase();
|
||||
@@ -50,7 +48,6 @@ public class TagsDataPrep extends RestTest
|
||||
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").toLowerCase()).create());
|
||||
folder2tags = restClient.withCoreAPI().usingResource(folder2).addTags(folderTagValue, documentTagValue);
|
||||
|
||||
// Allow indexing to complete.
|
||||
Utility.sleep(500, 60000, () ->
|
||||
|
||||
@@ -305,24 +305,7 @@ public class UpdateTagTests extends TagsDataPrep
|
||||
returnedModel = restClient.authenticateUser(adminUserModel).withCoreAPI().usingTag(orphanTag).update(newTagName);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
RestTagModel expected = RestTagModel.builder().id(orphanTag.getId()).tag(newTagName).create();
|
||||
returnedModel.assertThat().isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.TAGS })
|
||||
public void canUpdateTagAndGetCount()
|
||||
{
|
||||
STEP("Create an orphaned tag");
|
||||
String tagName = RandomData.getRandomName("tag").toLowerCase();
|
||||
RestTagModel createdTag = RestTagModel.builder().tag(tagName).create();
|
||||
RestTagModel tag = restClient.authenticateUser(adminUserModel).withCoreAPI().createSingleTag(createdTag);
|
||||
|
||||
STEP("Update tag and request the count field");
|
||||
String newTagName = RandomData.getRandomName("new").toLowerCase();
|
||||
returnedModel = restClient.authenticateUser(adminUserModel).withCoreAPI().include("count").usingTag(tag).update(newTagName);
|
||||
|
||||
restClient.assertStatusCodeIs(HttpStatus.OK);
|
||||
RestTagModel expected = RestTagModel.builder().id(tag.getId()).tag(newTagName).count(0).create();
|
||||
returnedModel.assertThat().isEqualTo(expected);
|
||||
returnedModel.assertThat().field("tag").is(newTagName);
|
||||
returnedModel.assertThat().field("id").isNotNull();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
BIN
packaging/war/src/main/webapp/images/logo/adw_logo.png
Normal file
BIN
packaging/war/src/main/webapp/images/logo/adw_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
BIN
packaging/war/src/main/webapp/images/logo/hyland_logo.png
Normal file
BIN
packaging/war/src/main/webapp/images/logo/hyland_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.0 KiB |
20
pom.xml
20
pom.xml
@@ -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>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Alfresco Community Repo Parent</name>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<properties>
|
||||
<acs.version.major>7</acs.version.major>
|
||||
<acs.version.minor>4</acs.version.minor>
|
||||
<acs.version.revision>1</acs.version.revision>
|
||||
<acs.version.revision>0</acs.version.revision>
|
||||
<acs.version.label />
|
||||
<amp.min.version>${acs.version.major}.0.0</amp.min.version>
|
||||
|
||||
@@ -52,12 +52,12 @@
|
||||
<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.1.0</dependency.alfresco-transform-service.version>
|
||||
<dependency.alfresco-transform-core.version>3.1.0</dependency.alfresco-transform-core.version>
|
||||
<dependency.alfresco-transform-service.version>2.1.0-A6</dependency.alfresco-transform-service.version>
|
||||
<dependency.alfresco-transform-core.version>3.1.0-A8</dependency.alfresco-transform-core.version>
|
||||
<dependency.alfresco-greenmail.version>6.5</dependency.alfresco-greenmail.version>
|
||||
<dependency.acs-event-model.version>0.0.18</dependency.acs-event-model.version>
|
||||
|
||||
<dependency.spring.version>5.3.27</dependency.spring.version>
|
||||
<dependency.spring.version>5.3.26</dependency.spring.version>
|
||||
<dependency.antlr.version>3.5.3</dependency.antlr.version>
|
||||
<dependency.jackson.version>2.15.0-rc1</dependency.jackson.version>
|
||||
<dependency.cxf.version>3.5.5</dependency.cxf.version>
|
||||
@@ -79,7 +79,7 @@
|
||||
<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.8.3</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>
|
||||
@@ -111,8 +111,8 @@
|
||||
<dependency.json-smart.version>2.4.10</dependency.json-smart.version>
|
||||
<dependency.jakarta-rpc-api.version>1.1.4</dependency.jakarta-rpc-api.version>
|
||||
|
||||
<alfresco.googledrive.version>3.4.0</alfresco.googledrive.version>
|
||||
<alfresco.aos-module.version>1.6.0</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>
|
||||
@@ -150,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>21.1</tag>
|
||||
<tag>HEAD</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -936,7 +936,7 @@
|
||||
<plugin>
|
||||
<groupId>io.fabric8</groupId>
|
||||
<artifactId>docker-maven-plugin</artifactId>
|
||||
<version>0.42.1</version>
|
||||
<version>0.42.0</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -38,10 +38,10 @@ 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, 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, Parameters parameters);
|
||||
Tag changeTag(StoreRef storeRef, String tagId, Tag tag);
|
||||
CollectionWithPagingInfo<Tag> getTags(String nodeId, Parameters params);
|
||||
|
||||
@Experimental
|
||||
|
||||
@@ -111,11 +111,6 @@ public class CategoriesImpl implements Categories
|
||||
category.setCount(categoriesCount.getOrDefault(category.getId(), 0));
|
||||
}
|
||||
|
||||
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||
{
|
||||
category.setPath(getCategoryPath(category));
|
||||
}
|
||||
|
||||
return category;
|
||||
}
|
||||
|
||||
@@ -133,10 +128,6 @@ public class CategoriesImpl implements Categories
|
||||
{
|
||||
category.setCount(0);
|
||||
}
|
||||
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||
{
|
||||
category.setPath(getCategoryPath(category));
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
@@ -145,18 +136,11 @@ public class CategoriesImpl implements Categories
|
||||
public List<Category> getCategoryChildren(final StoreRef storeRef, final String parentCategoryId, final Parameters parameters)
|
||||
{
|
||||
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)
|
||||
.peek(category -> {
|
||||
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||
{
|
||||
category.setPath(getCategoryPath(category));
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
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))
|
||||
{
|
||||
@@ -186,11 +170,6 @@ public class CategoriesImpl implements Categories
|
||||
category.setCount(categoriesCount.getOrDefault(category.getId(), 0));
|
||||
}
|
||||
|
||||
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||
{
|
||||
category.setPath(getCategoryPath(category));
|
||||
}
|
||||
|
||||
return category;
|
||||
}
|
||||
|
||||
@@ -221,16 +200,7 @@ public class CategoriesImpl implements Categories
|
||||
}
|
||||
final Collection<NodeRef> actualCategories = DefaultTypeConverter.INSTANCE.getCollection(NodeRef.class, currentCategories);
|
||||
|
||||
return actualCategories
|
||||
.stream()
|
||||
.map(this::mapToCategory)
|
||||
.peek(category -> {
|
||||
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||
{
|
||||
category.setPath(getCategoryPath(category));
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
return actualCategories.stream().map(this::mapToCategory).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -260,16 +230,7 @@ public class CategoriesImpl implements Categories
|
||||
|
||||
linkNodeToCategories(contentNodeRef, categoryNodeRefs);
|
||||
|
||||
return categoryNodeRefs
|
||||
.stream()
|
||||
.map(this::mapToCategory)
|
||||
.peek(category -> {
|
||||
if (parameters.getInclude().contains(Nodes.PARAM_INCLUDE_PATH))
|
||||
{
|
||||
category.setPath(getCategoryPath(category));
|
||||
}
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
return categoryNodeRefs.stream().map(this::mapToCategory).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -514,16 +475,4 @@ public class CategoriesImpl implements Categories
|
||||
.stream()
|
||||
.collect(Collectors.toMap(pair -> pair.getFirst().toString().replace(idPrefix, StringUtils.EMPTY), Pair::getSecond));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get path for a given category in human-readable form.
|
||||
*
|
||||
* @param category Category to provide path for.
|
||||
* @return Path for a category in human-readable form.
|
||||
*/
|
||||
private String getCategoryPath(final Category category)
|
||||
{
|
||||
final NodeRef categoryNodeRef = nodes.getNode(category.getId()).getNodeRef();
|
||||
return nodeService.getPath(categoryNodeRef).toDisplayPath(nodeService, permissionService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,13 +30,11 @@ 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 static org.alfresco.service.cmr.repository.StoreRef.STORE_REF_WORKSPACE_SPACESSTORE;
|
||||
import static org.alfresco.service.cmr.tagging.TaggingService.TAG_ROOT_NODE_REF;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -45,8 +43,6 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.query.ListBackedPagingResults;
|
||||
import org.alfresco.query.PagingResults;
|
||||
import org.alfresco.repo.tagging.NonExistentTagException;
|
||||
import org.alfresco.repo.tagging.TagExistsException;
|
||||
@@ -63,12 +59,10 @@ import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationE
|
||||
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.SortColumn;
|
||||
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.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
@@ -86,40 +80,40 @@ import org.apache.commons.collections.CollectionUtils;
|
||||
*/
|
||||
public class TagsImpl implements Tags
|
||||
{
|
||||
public 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 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 Nodes nodes;
|
||||
private NodeService nodeService;
|
||||
private TaggingService taggingService;
|
||||
private TypeConstraint typeConstraint;
|
||||
private AuthorityService authorityService;
|
||||
private NodeService nodeService;
|
||||
private TaggingService taggingService;
|
||||
private TypeConstraint typeConstraint;
|
||||
private AuthorityService authorityService;
|
||||
|
||||
public void setTypeConstraint(TypeConstraint typeConstraint)
|
||||
{
|
||||
this.typeConstraint = typeConstraint;
|
||||
}
|
||||
public void setTypeConstraint(TypeConstraint typeConstraint)
|
||||
{
|
||||
this.typeConstraint = typeConstraint;
|
||||
}
|
||||
|
||||
public void setNodes(Nodes nodes)
|
||||
public void setNodes(Nodes nodes)
|
||||
{
|
||||
this.nodes = nodes;
|
||||
}
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
this.nodes = nodes;
|
||||
}
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
this.nodeService = nodeService;
|
||||
}
|
||||
|
||||
public void setTaggingService(TaggingService taggingService)
|
||||
{
|
||||
this.taggingService = taggingService;
|
||||
}
|
||||
this.taggingService = taggingService;
|
||||
}
|
||||
|
||||
public void setAuthorityService(AuthorityService authorityService)
|
||||
{
|
||||
this.authorityService = authorityService;
|
||||
}
|
||||
public void setAuthorityService(AuthorityService authorityService)
|
||||
{
|
||||
this.authorityService = authorityService;
|
||||
}
|
||||
|
||||
public List<Tag> addTags(String nodeId, final List<Tag> tags, final Parameters parameters)
|
||||
{
|
||||
@@ -134,15 +128,14 @@ public class TagsImpl implements Tags
|
||||
{
|
||||
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, Long> tagsCountMap = tagsCountPairList.stream().collect(Collectors.toMap(Pair::getFirst, pair -> Long.valueOf(pair.getSecond())));
|
||||
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(0L) + 1);
|
||||
}
|
||||
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;
|
||||
@@ -152,112 +145,105 @@ public class TagsImpl implements Tags
|
||||
throw new InvalidArgumentException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void deleteTag(String nodeId, String tagId)
|
||||
{
|
||||
NodeRef nodeRef = nodes.validateNode(nodeId);
|
||||
getTag(STORE_REF_WORKSPACE_SPACESSTORE, tagId, null);
|
||||
NodeRef existingTagNodeRef = validateTag(tagId);
|
||||
String tagValue = taggingService.getTagName(existingTagNodeRef);
|
||||
taggingService.removeTag(nodeRef, tagValue);
|
||||
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();
|
||||
public void deleteTagById(StoreRef storeRef, String tagId) {
|
||||
verifyAdminAuthority();
|
||||
|
||||
NodeRef tagNodeRef = validateTag(storeRef, tagId);
|
||||
String tagValue = taggingService.getTagName(tagNodeRef);
|
||||
taggingService.deleteTag(storeRef, tagValue);
|
||||
}
|
||||
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();
|
||||
Pair<String, Boolean> sorting = !params.getSorting().isEmpty() ? new Pair<>(params.getSorting().get(0).column, params.getSorting().get(0).asc) : null;
|
||||
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));
|
||||
|
||||
Map<NodeRef, Long> results = taggingService.getTags(storeRef, params.getInclude(), sorting, namesFilters.get(EQUALS), namesFilters.get(MATCHES));
|
||||
|
||||
List<Tag> tagsList = results.entrySet().stream().map(entry -> new Tag(entry.getKey(), (String)nodeService.getProperty(entry.getKey(), ContentModel.PROP_NAME))).collect(Collectors.toList());
|
||||
|
||||
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)
|
||||
{
|
||||
Tag selectedTag = new Tag(pair.getFirst(), pair.getSecond());
|
||||
tags.add(selectedTag);
|
||||
}
|
||||
if (params.getInclude().contains(PARAM_INCLUDE_COUNT))
|
||||
{
|
||||
tagsList.forEach(tag -> tag.setCount(results.get(tag.getNodeRef())));
|
||||
List<Pair<String, Integer>> tagsByCount = taggingService.findTaggedNodesAndCountByTagName(storeRef);
|
||||
Map<String, Integer> tagsByCountMap = new HashMap<>();
|
||||
if (tagsByCount != null)
|
||||
{
|
||||
for (Pair<String, Integer> tagByCountElem : tagsByCount)
|
||||
{
|
||||
tagsByCountMap.put(tagByCountElem.getFirst(), tagByCountElem.getSecond());
|
||||
}
|
||||
}
|
||||
tags.forEach(tag -> tag.setCount(Optional.ofNullable(tagsByCountMap.get(tag.getTag())).orElse(0)));
|
||||
}
|
||||
|
||||
ListBackedPagingResults listBackedPagingResults = new ListBackedPagingResults(tagsList, Util.getPagingRequest(params.getPaging()));
|
||||
|
||||
return CollectionWithPagingInfo.asPaged(paging, listBackedPagingResults.getPage(), listBackedPagingResults.hasMoreItems(), (Integer) listBackedPagingResults.getTotalResultCount().getFirst());
|
||||
return CollectionWithPagingInfo.asPaged(paging, tags, results.hasMoreItems(), totalItems);
|
||||
}
|
||||
|
||||
public NodeRef validateTag(String tagId)
|
||||
{
|
||||
NodeRef tagNodeRef = nodes.validateNode(tagId);
|
||||
return checkTagRootAsNodePrimaryParent(tagId, tagNodeRef);
|
||||
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);
|
||||
NodeRef tagNodeRef = nodes.validateNode(storeRef, tagId);
|
||||
return checkTagRootAsNodePrimaryParent(tagId, tagNodeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the number of times the given tag is used (if requested).
|
||||
*
|
||||
* @param storeRef The store the tag is in.
|
||||
* @param tagName The name of the tag.
|
||||
* @param parameters The request parameters object containing the includes parameter.
|
||||
* @return The number of times the tag is applied, or null if "count" wasn't in the include parameter.
|
||||
*/
|
||||
private Long findCountIfRequested(StoreRef storeRef, String tagName, Parameters parameters)
|
||||
public Tag changeTag(StoreRef storeRef, String tagId, Tag tag)
|
||||
{
|
||||
Long count = null;
|
||||
if (parameters != null && parameters.getInclude() != null && parameters.getInclude().contains(PARAM_INCLUDE_COUNT))
|
||||
{
|
||||
count = taggingService.findCountByTagName(storeRef, tagName);
|
||||
}
|
||||
return count;
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag changeTag(StoreRef storeRef, String tagId, Tag tag, Parameters parameters)
|
||||
public Tag getTag(String tagId)
|
||||
{
|
||||
try
|
||||
{
|
||||
NodeRef existingTagNodeRef = validateTag(storeRef, tagId);
|
||||
String existingTagName = taggingService.getTagName(existingTagNodeRef);
|
||||
Long count = findCountIfRequested(storeRef, existingTagName, parameters);
|
||||
String newTagName = tag.getTag();
|
||||
NodeRef newTagNodeRef = taggingService.changeTag(storeRef, existingTagName, newTagName);
|
||||
return Tag.builder().nodeRef(newTagNodeRef).tag(newTagName).count(count).create();
|
||||
}
|
||||
catch(NonExistentTagException e)
|
||||
{
|
||||
throw new NotFoundException(e.getMessage());
|
||||
}
|
||||
catch(TagExistsException e)
|
||||
{
|
||||
throw new ConstraintViolatedException(e.getMessage());
|
||||
}
|
||||
catch(TaggingException e)
|
||||
{
|
||||
throw new InvalidArgumentException(e.getMessage());
|
||||
}
|
||||
return getTag(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, tagId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getTag(StoreRef storeRef, String tagId, Parameters parameters)
|
||||
public Tag getTag(StoreRef storeRef, String tagId)
|
||||
{
|
||||
NodeRef tagNodeRef = validateTag(storeRef, tagId);
|
||||
String tagName = taggingService.getTagName(tagNodeRef);
|
||||
Long count = findCountIfRequested(storeRef, tagName, parameters);
|
||||
return Tag.builder().nodeRef(tagNodeRef).tag(tagName).count(count).create();
|
||||
NodeRef tagNodeRef = validateTag(storeRef, tagId);
|
||||
String tagValue = taggingService.getTagName(tagNodeRef);
|
||||
return new Tag(tagNodeRef, tagValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionWithPagingInfo<Tag> getTags(String nodeId, Parameters params)
|
||||
{
|
||||
NodeRef nodeRef = nodes.validateOrLookupNode(nodeId);
|
||||
@@ -273,80 +259,80 @@ public class TagsImpl implements Tags
|
||||
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());
|
||||
@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);
|
||||
}
|
||||
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(0L);
|
||||
}
|
||||
}).collect(toList());
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
/**
|
||||
* 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();
|
||||
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))));
|
||||
}
|
||||
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(TAG_ROOT_NODE_REF))
|
||||
{
|
||||
throw new EntityNotFoundException(tagId);
|
||||
}
|
||||
return tagNodeRef;
|
||||
}
|
||||
private NodeRef checkTagRootAsNodePrimaryParent(String tagId, NodeRef tagNodeRef)
|
||||
{
|
||||
if ( tagNodeRef == null || !nodeService.getPrimaryParent(tagNodeRef).getParentRef().equals(TAG_ROOT_NODE_REF))
|
||||
{
|
||||
throw new EntityNotFoundException(tagId);
|
||||
}
|
||||
return tagNodeRef;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ public class Category
|
||||
private String parentId;
|
||||
private boolean hasChildren;
|
||||
private Integer count;
|
||||
private String path;
|
||||
|
||||
public String getId()
|
||||
{
|
||||
@@ -92,14 +91,6 @@ public class Category
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
@@ -109,20 +100,19 @@ public class Category
|
||||
return false;
|
||||
Category category = (Category) o;
|
||||
return hasChildren == category.hasChildren && Objects.equals(id, category.id) && Objects.equals(name, category.name) && Objects.equals(parentId, category.parentId)
|
||||
&& Objects.equals(count, category.count) && Objects.equals(path, category.path);
|
||||
&& Objects.equals(count, category.count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hash(id, name, parentId, hasChildren, count, path);
|
||||
return Objects.hash(id, name, parentId, hasChildren, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Category{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", parentId='" + parentId + '\'' + ", hasChildren=" + hasChildren
|
||||
+ ", count=" + count + ", path=" + path + '}';
|
||||
return "Category{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", parentId='" + parentId + '\'' + ", hasChildren=" + hasChildren + ", count=" + count + '}';
|
||||
}
|
||||
|
||||
public static Builder builder()
|
||||
@@ -137,7 +127,6 @@ public class Category
|
||||
private String parentId;
|
||||
private boolean hasChildren;
|
||||
private Integer count;
|
||||
private String path;
|
||||
|
||||
public Builder id(String id)
|
||||
{
|
||||
@@ -169,12 +158,6 @@ public class Category
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder path(String path)
|
||||
{
|
||||
this.path = path;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Category create()
|
||||
{
|
||||
final Category category = new Category();
|
||||
@@ -183,7 +166,6 @@ public class Category
|
||||
category.setParentId(parentId);
|
||||
category.setHasChildren(hasChildren);
|
||||
category.setCount(count);
|
||||
category.setPath(path);
|
||||
return category;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class Tag implements Comparable<Tag>
|
||||
{
|
||||
private NodeRef nodeRef;
|
||||
private String tag;
|
||||
private Long count;
|
||||
private Integer count;
|
||||
|
||||
public Tag()
|
||||
{
|
||||
@@ -76,13 +76,13 @@ public class Tag implements Comparable<Tag>
|
||||
this.tag = Optional.ofNullable(tag).map(String::toLowerCase).orElse(null);
|
||||
}
|
||||
|
||||
public Long getCount()
|
||||
public Integer getCount()
|
||||
{
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setCount(Long count)
|
||||
public void setCount(Integer count)
|
||||
{
|
||||
this.count = count;
|
||||
}
|
||||
@@ -133,7 +133,7 @@ public class Tag implements Comparable<Tag>
|
||||
{
|
||||
private NodeRef nodeRef;
|
||||
private String tag;
|
||||
private Long count;
|
||||
private Integer count;
|
||||
|
||||
public Builder nodeRef(NodeRef nodeRef)
|
||||
{
|
||||
@@ -147,7 +147,7 @@ public class Tag implements Comparable<Tag>
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder count(Long count)
|
||||
public Builder count(Integer count)
|
||||
{
|
||||
this.count = count;
|
||||
return this;
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
*/
|
||||
package org.alfresco.rest.api.tags;
|
||||
|
||||
import java.util.List;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.rest.api.Tags;
|
||||
import org.alfresco.rest.api.model.Tag;
|
||||
@@ -73,13 +73,13 @@ public class TagsEntityResource implements EntityResourceAction.Read<Tag>,
|
||||
@WebApiDescription(title="Updates a tag by unique Id")
|
||||
public Tag update(String id, Tag entity, Parameters parameters)
|
||||
{
|
||||
return tags.changeTag(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id, entity, parameters);
|
||||
return tags.changeTag(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag readById(String id, Parameters parameters) throws EntityNotFoundException
|
||||
{
|
||||
return tags.getTag(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id, parameters);
|
||||
return tags.getTag(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -60,7 +60,6 @@ import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.transfer.PathHelper;
|
||||
import org.alfresco.rest.api.Nodes;
|
||||
import org.alfresco.rest.api.model.Category;
|
||||
import org.alfresco.rest.api.model.Node;
|
||||
@@ -72,7 +71,6 @@ import org.alfresco.rest.framework.resource.parameters.Parameters;
|
||||
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.Path;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.CategoryService;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
@@ -102,9 +100,6 @@ public class CategoriesImplTest
|
||||
private static final Category CATEGORY = createDefaultCategory();
|
||||
private static final String CONTENT_NODE_ID = "content-node-id";
|
||||
private static final NodeRef CONTENT_NODE_REF = createNodeRefWithId(CONTENT_NODE_ID);
|
||||
private static final String MOCK_ROOT_LEVEL = "/{mockRootLevel}";
|
||||
private static final String MOCK_CHILD_LEVEL = "/{mockChild}";
|
||||
private static final String MOCK_CATEGORY_PATH = "//" + MOCK_ROOT_LEVEL + "//" + MOCK_CHILD_LEVEL;
|
||||
|
||||
@Mock
|
||||
private Nodes nodesMock;
|
||||
@@ -257,27 +252,6 @@ public class CategoriesImplTest
|
||||
.isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCategoryById_includePath()
|
||||
{
|
||||
final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
|
||||
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
|
||||
final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
|
||||
given(nodesMock.getNode(any())).willReturn(createNode());
|
||||
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
|
||||
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||
|
||||
// when
|
||||
final Category actualCategory = objectUnderTest.getCategoryById(CATEGORY_ID, parametersMock);
|
||||
|
||||
assertThat(actualCategory)
|
||||
.isNotNull()
|
||||
.extracting(Category::getPath)
|
||||
.isNotNull()
|
||||
.isEqualTo(MOCK_CATEGORY_PATH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCategoryById_notACategory()
|
||||
{
|
||||
@@ -505,36 +479,6 @@ public class CategoriesImplTest
|
||||
.isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateCategory_includePath()
|
||||
{
|
||||
final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
|
||||
final NodeRef categoryNodeRef = createNodeRefWithId(CATEGORY_ID);
|
||||
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
|
||||
final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
|
||||
given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
|
||||
given(categoryServiceMock.createCategory(parentCategoryNodeRef, CATEGORY_NAME)).willReturn(categoryNodeRef);
|
||||
given(nodesMock.getNode(any())).willReturn(createNode());
|
||||
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
|
||||
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||
final List<Category> categoryModels = new ArrayList<>(prepareCategories());
|
||||
|
||||
// when
|
||||
final List<Category> actualCreatedCategories = objectUnderTest.createSubcategories(PARENT_ID, categoryModels, parametersMock);
|
||||
|
||||
then(categoryServiceMock).should().createCategory(any(), any());
|
||||
then(categoryServiceMock).shouldHaveNoMoreInteractions();
|
||||
|
||||
assertThat(actualCreatedCategories)
|
||||
.isNotNull()
|
||||
.hasSize(1)
|
||||
.element(0)
|
||||
.extracting(Category::getPath)
|
||||
.isNotNull()
|
||||
.isEqualTo(MOCK_CATEGORY_PATH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateCategories_noPermissions()
|
||||
{
|
||||
@@ -684,30 +628,6 @@ public class CategoriesImplTest
|
||||
.isEqualTo(List.of(0, 2, 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCategoryChildren_includePath()
|
||||
{
|
||||
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
|
||||
given(nodesMock.validateNode(PARENT_ID)).willReturn(parentCategoryNodeRef);
|
||||
given(nodesMock.isSubClass(parentCategoryNodeRef, ContentModel.TYPE_CATEGORY, false)).willReturn(true);
|
||||
final int childrenCount = 3;
|
||||
final List<ChildAssociationRef> childAssociationRefMocks = prepareChildAssocMocks(childrenCount, parentCategoryNodeRef);
|
||||
given(nodeServiceMock.getChildAssocs(parentCategoryNodeRef)).willReturn(childAssociationRefMocks);
|
||||
childAssociationRefMocks.forEach(this::prepareCategoryNodeMocks);
|
||||
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||
|
||||
// when
|
||||
final List<Category> actualCategoryChildren = objectUnderTest.getCategoryChildren(PARENT_ID, parametersMock);
|
||||
|
||||
assertThat(actualCategoryChildren)
|
||||
.isNotNull()
|
||||
.hasSize(3)
|
||||
.extracting(Category::getPath)
|
||||
.isNotNull()
|
||||
.isEqualTo(List.of(MOCK_CATEGORY_PATH, MOCK_CATEGORY_PATH, MOCK_CATEGORY_PATH));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetCategoryChildren_noChildren()
|
||||
{
|
||||
@@ -831,32 +751,6 @@ public class CategoriesImplTest
|
||||
.isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateCategoryById_includePath()
|
||||
{
|
||||
final String categoryNewName = "categoryNewName";
|
||||
final Category fixedCategory = createCategoryOnlyWithName(categoryNewName);
|
||||
// simulate path provided by client to check if it will be ignored
|
||||
fixedCategory.setPath("/test/TestCat");
|
||||
final QName categoryQName = createCmQNameOf(CATEGORY_NAME);
|
||||
final NodeRef parentCategoryNodeRef = createNodeRefWithId(PARENT_ID);
|
||||
final ChildAssociationRef parentAssociation = createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, categoryQName);
|
||||
given(nodesMock.getNode(any())).willReturn(createNode(categoryNewName));
|
||||
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
|
||||
given(nodeServiceMock.moveNode(any(), any(), any(), any())).willReturn(createAssociationOf(parentCategoryNodeRef, CATEGORY_NODE_REF, createCmQNameOf(categoryNewName)));
|
||||
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||
|
||||
// when
|
||||
final Category actualCategory = objectUnderTest.updateCategoryById(CATEGORY_ID, fixedCategory, parametersMock);
|
||||
|
||||
assertThat(actualCategory)
|
||||
.isNotNull()
|
||||
.extracting(Category::getPath)
|
||||
.isNotNull()
|
||||
.isEqualTo(MOCK_CATEGORY_PATH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateCategoryById_noPermission()
|
||||
{
|
||||
@@ -1024,7 +918,6 @@ public class CategoriesImplTest
|
||||
then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef);
|
||||
then(nodeServiceMock).shouldHaveNoMoreInteractions();
|
||||
final List<Category> expectedLinkedCategories = List.of(CATEGORY);
|
||||
expectedLinkedCategories.get(0).setPath(null);
|
||||
assertThat(actualLinkedCategories)
|
||||
.isNotNull().usingRecursiveComparison()
|
||||
.isEqualTo(expectedLinkedCategories);
|
||||
@@ -1091,36 +984,6 @@ public class CategoriesImplTest
|
||||
.isEqualTo(expectedLinkedCategories);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLinkNodeToCategories_includePath()
|
||||
{
|
||||
final NodeRef categoryParentNodeRef = createNodeRefWithId(PARENT_ID);
|
||||
final ChildAssociationRef parentAssociation = createAssociationOf(categoryParentNodeRef, CATEGORY_NODE_REF);
|
||||
given(nodesMock.getNode(any())).willReturn(createNode());
|
||||
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
|
||||
given(nodeServiceMock.hasAspect(any(), any())).willReturn(true);
|
||||
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||
|
||||
// when
|
||||
final List<Category> actualLinkedCategories = objectUnderTest.linkNodeToCategories(CONTENT_NODE_ID, List.of(CATEGORY), parametersMock);
|
||||
|
||||
then(nodesMock).should(times(2)).getNode(CATEGORY_ID);
|
||||
then(nodeServiceMock).should().getChildAssocs(CATEGORY_NODE_REF, RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL, false);
|
||||
then(nodeServiceMock).should().getPrimaryParent(CATEGORY_NODE_REF);
|
||||
then(nodeServiceMock).should().getParentAssocs(CATEGORY_NODE_REF);
|
||||
then(nodeServiceMock).should().hasAspect(CONTENT_NODE_REF, ContentModel.ASPECT_GEN_CLASSIFIABLE);
|
||||
then(nodeServiceMock).should().getProperty(CONTENT_NODE_REF, ContentModel.PROP_CATEGORIES);
|
||||
final Serializable expectedCategories = (Serializable) List.of(CATEGORY_NODE_REF);
|
||||
then(nodeServiceMock).should().setProperty(CONTENT_NODE_REF, ContentModel.PROP_CATEGORIES, expectedCategories);
|
||||
then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef);
|
||||
final List<Category> expectedLinkedCategories = List.of(CATEGORY);
|
||||
expectedLinkedCategories.get(0).setPath(MOCK_CATEGORY_PATH);
|
||||
assertThat(actualLinkedCategories)
|
||||
.isNotNull().usingRecursiveComparison()
|
||||
.isEqualTo(expectedLinkedCategories);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLinkNodeToCategories_withPreviouslyLinkedCategories()
|
||||
{
|
||||
@@ -1305,46 +1168,11 @@ public class CategoriesImplTest
|
||||
then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef);
|
||||
then(nodeServiceMock).shouldHaveNoMoreInteractions();
|
||||
final List<Category> expectedCategories = List.of(CATEGORY);
|
||||
expectedCategories.get(0).setPath(null);
|
||||
assertThat(actualCategories)
|
||||
.isNotNull().usingRecursiveComparison()
|
||||
.isEqualTo(expectedCategories);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListCategoriesForNode_includePath()
|
||||
{
|
||||
final NodeRef categoryParentNodeRef = createNodeRefWithId(PARENT_ID);
|
||||
final ChildAssociationRef parentAssociation = createAssociationOf(categoryParentNodeRef, CATEGORY_NODE_REF);
|
||||
given(nodeServiceMock.getProperty(any(), eq(ContentModel.PROP_CATEGORIES))).willReturn((Serializable) List.of(CATEGORY_NODE_REF));
|
||||
given(nodesMock.getNode(any())).willReturn(createNode());
|
||||
given(nodeServiceMock.getPrimaryParent(any())).willReturn(parentAssociation);
|
||||
given(parametersMock.getInclude()).willReturn(List.of(Nodes.PARAM_INCLUDE_PATH));
|
||||
given(nodeServiceMock.getPath(any())).willReturn(mockCategoryPath());
|
||||
|
||||
// when
|
||||
final List<Category> actualCategories = objectUnderTest.listCategoriesForNode(CONTENT_NODE_ID, parametersMock);
|
||||
|
||||
then(nodesMock).should().validateOrLookupNode(CONTENT_NODE_ID);
|
||||
then(permissionServiceMock).should().hasReadPermission(CONTENT_NODE_REF);
|
||||
then(permissionServiceMock).shouldHaveNoMoreInteractions();
|
||||
then(typeConstraint).should().matches(CONTENT_NODE_REF);
|
||||
then(typeConstraint).shouldHaveNoMoreInteractions();
|
||||
then(nodesMock).should(times(2)).getNode(CATEGORY_ID);
|
||||
then(nodesMock).shouldHaveNoMoreInteractions();
|
||||
then(nodeServiceMock).should().getProperty(CONTENT_NODE_REF, ContentModel.PROP_CATEGORIES);
|
||||
then(nodeServiceMock).should().getChildAssocs(CATEGORY_NODE_REF, RegexQNamePattern.MATCH_ALL, RegexQNamePattern.MATCH_ALL, false);
|
||||
then(nodeServiceMock).should().getPrimaryParent(CATEGORY_NODE_REF);
|
||||
then(nodeServiceMock).should().getParentAssocs(categoryParentNodeRef);
|
||||
then(nodeServiceMock).should().getPath(any());
|
||||
then(nodeServiceMock).shouldHaveNoMoreInteractions();
|
||||
final List<Category> expectedCategories = List.of(CATEGORY);
|
||||
expectedCategories.get(0).setPath(MOCK_CATEGORY_PATH);
|
||||
assertThat(actualCategories)
|
||||
.isNotNull().usingRecursiveComparison()
|
||||
.isEqualTo(expectedCategories);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListCategoriesForNode_withInvalidNodeId()
|
||||
{
|
||||
@@ -1501,13 +1329,4 @@ public class CategoriesImplTest
|
||||
{
|
||||
return new ChildAssociationRef(ContentModel.ASSOC_SUBCATEGORIES, parentNode, childNodeName, childNode);
|
||||
}
|
||||
|
||||
private Path mockCategoryPath()
|
||||
{
|
||||
final Path mockPath = new Path();
|
||||
mockPath.append(PathHelper.stringToPath(MOCK_ROOT_LEVEL));
|
||||
mockPath.append(PathHelper.stringToPath(MOCK_CHILD_LEVEL));
|
||||
mockPath.append(PathHelper.stringToPath("/"));
|
||||
return mockPath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,14 +40,10 @@ import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.query.PagingRequest;
|
||||
import org.alfresco.query.PagingResults;
|
||||
import org.alfresco.rest.api.Nodes;
|
||||
@@ -59,7 +55,6 @@ import org.alfresco.rest.framework.core.exceptions.UnsupportedResourceOperationE
|
||||
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.SortColumn;
|
||||
import org.alfresco.rest.framework.resource.parameters.where.InvalidQueryException;
|
||||
import org.alfresco.rest.framework.tools.RecognizedParamsExtractor;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
@@ -88,8 +83,6 @@ public class TagsImplTest
|
||||
private static final NodeRef TAG_PARENT_NODE_REF = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, PARENT_NODE_ID);
|
||||
private static final String CONTENT_NODE_ID = "content-node-id";
|
||||
private static final NodeRef CONTENT_NODE_REF = new NodeRef(STORE_REF_WORKSPACE_SPACESSTORE, CONTENT_NODE_ID);
|
||||
private static final String PARAM_INCLUDE_COUNT = "count";
|
||||
|
||||
|
||||
private final RecognizedParamsExtractor queryExtractor = new RecognizedParamsExtractor() {};
|
||||
|
||||
@@ -122,23 +115,19 @@ public class TagsImplTest
|
||||
given(nodesMock.validateNode(STORE_REF_WORKSPACE_SPACESSTORE, TAG_ID)).willReturn(TAG_NODE_REF);
|
||||
given(taggingServiceMock.getTagName(TAG_NODE_REF)).willReturn(TAG_NAME);
|
||||
given(nodeServiceMock.getPrimaryParent(TAG_NODE_REF)).willReturn(primaryParentMock);
|
||||
given(primaryParentMock.getParentRef()).willReturn(TAG_PARENT_NODE_REF);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTags()
|
||||
{
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||
given(parametersMock.getInclude()).willReturn(new ArrayList<>());
|
||||
|
||||
//given(taggingServiceMock.getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(), any(), isNull(), isNull())).willReturn(List.of(new Pair<>(TAG_NODE_REF, null)));
|
||||
given(taggingServiceMock.getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(), any(), isNull(), isNull())).willReturn(Map.of(TAG_NODE_REF, 0L));
|
||||
given(nodeServiceMock.getProperty(any(NodeRef.class), eq(ContentModel.PROP_NAME))).willReturn("tag-dummy-name");
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
||||
given(pagingResultsMock.getPage()).willReturn(List.of(new Pair<>(TAG_NODE_REF, TAG_NAME)));
|
||||
|
||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||
|
||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(), any(), isNull(), isNull());
|
||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(PagingRequest.class), isNull(), isNull());
|
||||
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
||||
final List<Tag> expectedTags = createTagsWithNodeRefs(List.of(TAG_NAME));
|
||||
assertEquals(expectedTags, actualTags.getCollection());
|
||||
@@ -148,17 +137,16 @@ public class TagsImplTest
|
||||
public void testGetTags_verifyIfCountIsZero()
|
||||
{
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||
given(parametersMock.getInclude()).willReturn(List.of(PARAM_INCLUDE_COUNT));
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(), any(), any(), any())).willReturn(Map.of(TAG_NODE_REF, 0L));
|
||||
|
||||
given(nodeServiceMock.getProperty(any(NodeRef.class), eq(ContentModel.PROP_NAME))).willReturn("tag-dummy-name");
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
||||
given(pagingResultsMock.getPage()).willReturn(List.of(new Pair<>(TAG_NODE_REF, TAG_NAME)));
|
||||
given(parametersMock.getInclude()).willReturn(List.of("count"));
|
||||
|
||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||
|
||||
then(taggingServiceMock).should().findTaggedNodesAndCountByTagName(STORE_REF_WORKSPACE_SPACESSTORE);
|
||||
final List<Tag> expectedTags = createTagsWithNodeRefs(List.of(TAG_NAME)).stream()
|
||||
.peek(tag -> tag.setCount(0L))
|
||||
.peek(tag -> tag.setCount(0))
|
||||
.collect(toList());
|
||||
assertEquals(expectedTags, actualTags.getCollection());
|
||||
}
|
||||
@@ -169,142 +157,21 @@ public class TagsImplTest
|
||||
{
|
||||
NodeRef tagNodeA = new NodeRef("tag://A/");
|
||||
NodeRef tagNodeB = new NodeRef("tag://B/");
|
||||
List<Pair<NodeRef, String>> tagPairs = List.of(new Pair<>(tagNodeA, "taga"), new Pair<>(tagNodeB, "tagb"));
|
||||
|
||||
given(parametersMock.getSorting()).willReturn(Collections.emptyList());
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
||||
given(pagingResultsMock.getPage()).willReturn(tagPairs);
|
||||
given(parametersMock.getInclude()).willReturn(List.of("count"));
|
||||
|
||||
final LinkedHashMap<NodeRef, Long> results = new LinkedHashMap<>();
|
||||
results.put(tagNodeA, 5L);
|
||||
results.put(tagNodeB, 0L);
|
||||
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), eq(List.of(PARAM_INCLUDE_COUNT)), isNull(), any(), any())).willReturn(results);
|
||||
given(nodeServiceMock.getProperty(any(NodeRef.class), eq(ContentModel.PROP_NAME))).willReturn("taga", "tagb");
|
||||
// Only taga is included in the returned list since tagb is not in use.
|
||||
given(taggingServiceMock.findTaggedNodesAndCountByTagName(STORE_REF_WORKSPACE_SPACESSTORE)).willReturn(List.of(new Pair<>("taga", 5)));
|
||||
|
||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||
|
||||
final List<Tag> expectedTags = List.of(Tag.builder().tag("tagA").nodeRef(tagNodeA).count(5L).create(),
|
||||
Tag.builder().tag("tagB").nodeRef(tagNodeB).count(0L).create());
|
||||
assertEquals(expectedTags, actualTags.getCollection());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTags_orderByCountAscendingOrder()
|
||||
{
|
||||
NodeRef tagNodeA = new NodeRef("tag://A/");
|
||||
NodeRef tagNodeB = new NodeRef("tag://B/");
|
||||
NodeRef tagNodeC = new NodeRef("tag://C/");
|
||||
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getInclude()).willReturn(List.of("count"));
|
||||
given(parametersMock.getSorting()).willReturn(List.of(new SortColumn("count", true)));
|
||||
|
||||
final LinkedHashMap<NodeRef, Long> results = new LinkedHashMap<>();
|
||||
results.put(tagNodeB, 0L);
|
||||
results.put(tagNodeC, 2L);
|
||||
results.put(tagNodeA, 5L);
|
||||
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), eq(List.of(PARAM_INCLUDE_COUNT)), eq(new Pair<>("count", true)), any(), any())).willReturn(results);
|
||||
given(nodeServiceMock.getProperty(tagNodeA, ContentModel.PROP_NAME)).willReturn("taga");
|
||||
given(nodeServiceMock.getProperty(tagNodeB, ContentModel.PROP_NAME)).willReturn("tagb");
|
||||
given(nodeServiceMock.getProperty(tagNodeC, ContentModel.PROP_NAME)).willReturn("tagc");
|
||||
|
||||
//when
|
||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||
|
||||
final List<Tag> expectedTags = List.of(Tag.builder().tag("tagb").nodeRef(tagNodeB).count(0L).create(),
|
||||
Tag.builder().tag("tagc").nodeRef(tagNodeC).count(2L).create(),
|
||||
Tag.builder().tag("taga").nodeRef(tagNodeA).count(5L).create());
|
||||
assertEquals(expectedTags, actualTags.getCollection());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTags_orderByCountDescendingOrder()
|
||||
{
|
||||
NodeRef tagNodeA = new NodeRef("tag://A/");
|
||||
NodeRef tagNodeB = new NodeRef("tag://B/");
|
||||
NodeRef tagNodeC = new NodeRef("tag://C/");
|
||||
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getInclude()).willReturn(List.of("count"));
|
||||
given(parametersMock.getSorting()).willReturn(List.of(new SortColumn("count", false)));
|
||||
|
||||
final LinkedHashMap<NodeRef, Long> results = new LinkedHashMap<>();
|
||||
results.put(tagNodeA, 5L);
|
||||
results.put(tagNodeC, 2L);
|
||||
results.put(tagNodeB, 0L);
|
||||
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), eq(List.of(PARAM_INCLUDE_COUNT)), eq(new Pair<>("count", false)), any(), any())).willReturn(results);
|
||||
given(nodeServiceMock.getProperty(tagNodeA, ContentModel.PROP_NAME)).willReturn("taga");
|
||||
given(nodeServiceMock.getProperty(tagNodeB, ContentModel.PROP_NAME)).willReturn("tagb");
|
||||
given(nodeServiceMock.getProperty(tagNodeC, ContentModel.PROP_NAME)).willReturn("tagc");
|
||||
|
||||
//when
|
||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||
|
||||
final List<Tag> expectedTags = List.of(Tag.builder().tag("taga").nodeRef(tagNodeA).count(5L).create(),
|
||||
Tag.builder().tag("tagc").nodeRef(tagNodeC).count(2L).create(),
|
||||
Tag.builder().tag("tagb").nodeRef(tagNodeB).count(0L).create());
|
||||
assertEquals(expectedTags, actualTags.getCollection());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTags_orderByTagAscendingOrder()
|
||||
{
|
||||
NodeRef tagApple = new NodeRef("tag://apple/");
|
||||
NodeRef tagBanana = new NodeRef("tag://banana/");
|
||||
NodeRef tagCoconut = new NodeRef("tag://coconut/");
|
||||
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getInclude()).willReturn(Collections.emptyList());
|
||||
given(parametersMock.getSorting()).willReturn(List.of(new SortColumn("tag", true)));
|
||||
|
||||
final LinkedHashMap<NodeRef, Long> results = new LinkedHashMap<>();
|
||||
results.put(tagApple, 0L);
|
||||
results.put(tagBanana, 0L);
|
||||
results.put(tagCoconut, 0L);
|
||||
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(), eq(new Pair<>("tag", true)), any(), any())).willReturn(results);
|
||||
given(nodeServiceMock.getProperty(tagApple, ContentModel.PROP_NAME)).willReturn("apple");
|
||||
given(nodeServiceMock.getProperty(tagBanana, ContentModel.PROP_NAME)).willReturn("banana");
|
||||
given(nodeServiceMock.getProperty(tagCoconut, ContentModel.PROP_NAME)).willReturn("coconut");
|
||||
|
||||
//when
|
||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||
|
||||
final List<Tag> expectedTags = List.of(Tag.builder().tag("apple").nodeRef(tagApple).create(),
|
||||
Tag.builder().tag("banana").nodeRef(tagBanana).create(),
|
||||
Tag.builder().tag("coconut").nodeRef(tagCoconut).create());
|
||||
assertEquals(expectedTags, actualTags.getCollection());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTags_orderByTagDescendingOrder()
|
||||
{
|
||||
NodeRef tagApple = new NodeRef("tag://apple/");
|
||||
NodeRef tagBanana = new NodeRef("tag://banana/");
|
||||
NodeRef tagCoconut = new NodeRef("tag://coconut/");
|
||||
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getInclude()).willReturn(Collections.emptyList());
|
||||
given(parametersMock.getSorting()).willReturn(List.of(new SortColumn("tag", false)));
|
||||
|
||||
final LinkedHashMap<NodeRef, Long> results = new LinkedHashMap<>();
|
||||
results.put(tagCoconut, 0L);
|
||||
results.put(tagBanana, 0L);
|
||||
results.put(tagApple, 0L);
|
||||
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(), eq(new Pair<>("tag", false)), any(), any())).willReturn(results);
|
||||
given(nodeServiceMock.getProperty(tagApple, ContentModel.PROP_NAME)).willReturn("apple");
|
||||
given(nodeServiceMock.getProperty(tagBanana, ContentModel.PROP_NAME)).willReturn("banana");
|
||||
given(nodeServiceMock.getProperty(tagCoconut, ContentModel.PROP_NAME)).willReturn("coconut");
|
||||
|
||||
//when
|
||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||
|
||||
final List<Tag> expectedTags = List.of(Tag.builder().tag("coconut").nodeRef(tagCoconut).create(),
|
||||
Tag.builder().tag("banana").nodeRef(tagBanana).create(),
|
||||
Tag.builder().tag("apple").nodeRef(tagApple).create());
|
||||
then(taggingServiceMock).should().findTaggedNodesAndCountByTagName(STORE_REF_WORKSPACE_SPACESSTORE);
|
||||
final List<Tag> expectedTags = List.of(Tag.builder().tag("taga").nodeRef(tagNodeA).count(5).create(),
|
||||
Tag.builder().tag("tagb").nodeRef(tagNodeB).count(0).create());
|
||||
assertEquals(expectedTags, actualTags.getCollection());
|
||||
}
|
||||
|
||||
@@ -313,13 +180,13 @@ public class TagsImplTest
|
||||
{
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag=expectedName)"));
|
||||
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||
given(parametersMock.getInclude()).willReturn(new ArrayList<>());
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
||||
|
||||
//when
|
||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||
|
||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), eq(new ArrayList<>()), any(), eq(Set.of("expectedname")), isNull());
|
||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(PagingRequest.class), eq(Set.of("expectedname")), isNull());
|
||||
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
||||
assertThat(actualTags).isNotNull();
|
||||
}
|
||||
@@ -329,13 +196,13 @@ public class TagsImplTest
|
||||
{
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag IN (expectedName1, expectedName2))"));
|
||||
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||
given(parametersMock.getInclude()).willReturn(new ArrayList<>());
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
||||
|
||||
//when
|
||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||
|
||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE),any(), any(), eq(Set.of("expectedname1", "expectedname2")), isNull());
|
||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(PagingRequest.class), eq(Set.of("expectedname1", "expectedname2")), isNull());
|
||||
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
||||
assertThat(actualTags).isNotNull();
|
||||
}
|
||||
@@ -345,13 +212,13 @@ public class TagsImplTest
|
||||
{
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag MATCHES ('expectedName*'))"));
|
||||
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||
given(parametersMock.getInclude()).willReturn(new ArrayList<>());
|
||||
given(taggingServiceMock.getTags(any(StoreRef.class), any(PagingRequest.class), any(), any())).willReturn(pagingResultsMock);
|
||||
given(pagingResultsMock.getTotalResultCount()).willReturn(new Pair<>(Integer.MAX_VALUE, 0));
|
||||
|
||||
//when
|
||||
final CollectionWithPagingInfo<Tag> actualTags = objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock);
|
||||
|
||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(), any(), isNull(), eq(Set.of("expectedname*")));
|
||||
then(taggingServiceMock).should().getTags(eq(STORE_REF_WORKSPACE_SPACESSTORE), any(PagingRequest.class), isNull(), eq(Set.of("expectedname*")));
|
||||
then(taggingServiceMock).shouldHaveNoMoreInteractions();
|
||||
assertThat(actualTags).isNotNull();
|
||||
}
|
||||
@@ -361,7 +228,6 @@ public class TagsImplTest
|
||||
{
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag=expectedName AND tag IN (expectedName1, expectedName2))"));
|
||||
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||
|
||||
//when
|
||||
final Throwable actualException = catchThrowable(() -> objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock));
|
||||
@@ -375,7 +241,6 @@ public class TagsImplTest
|
||||
{
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(tag BETWEEN ('expectedName', 'expectedName2'))"));
|
||||
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||
|
||||
//when
|
||||
final Throwable actualException = catchThrowable(() -> objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock));
|
||||
@@ -389,7 +254,6 @@ public class TagsImplTest
|
||||
{
|
||||
given(parametersMock.getPaging()).willReturn(pagingMock);
|
||||
given(parametersMock.getQuery()).willReturn(queryExtractor.getWhereClause("(NOT tag=expectedName)"));
|
||||
given(parametersMock.getSorting()).willReturn(new ArrayList<>());
|
||||
|
||||
//when
|
||||
final Throwable actualException = catchThrowable(() -> objectUnderTest.getTags(STORE_REF_WORKSPACE_SPACESSTORE, parametersMock));
|
||||
@@ -402,6 +266,7 @@ public class TagsImplTest
|
||||
public void testDeleteTagById()
|
||||
{
|
||||
//when
|
||||
given(primaryParentMock.getParentRef()).willReturn(TAG_PARENT_NODE_REF);
|
||||
objectUnderTest.deleteTagById(STORE_REF_WORKSPACE_SPACESSTORE, TAG_ID);
|
||||
|
||||
then(authorityServiceMock).should().hasAdminAuthority();
|
||||
@@ -560,7 +425,7 @@ public class TagsImplTest
|
||||
final List<Tag> actualCreatedTags = objectUnderTest.createTags(tagsToCreate, parametersMock);
|
||||
|
||||
final List<Tag> expectedTags = createTagsWithNodeRefs(tagNames).stream()
|
||||
.peek(tag -> tag.setCount(0L))
|
||||
.peek(tag -> tag.setCount(0))
|
||||
.collect(toList());
|
||||
assertThat(actualCreatedTags)
|
||||
.isNotNull()
|
||||
@@ -570,8 +435,8 @@ public class TagsImplTest
|
||||
@Test(expected = EntityNotFoundException.class)
|
||||
public void testGetTagByIdNotFoundValidation()
|
||||
{
|
||||
given(nodesMock.validateNode(STORE_REF_WORKSPACE_SPACESSTORE, TAG_ID)).willThrow(EntityNotFoundException.class);
|
||||
objectUnderTest.getTag(STORE_REF_WORKSPACE_SPACESSTORE, TAG_ID, null);
|
||||
given(primaryParentMock.getParentRef()).willReturn(TAG_NODE_REF);
|
||||
objectUnderTest.getTag(STORE_REF_WORKSPACE_SPACESSTORE,TAG_ID);
|
||||
then(nodeServiceMock).shouldHaveNoInteractions();
|
||||
then(nodesMock).should().validateNode(STORE_REF_WORKSPACE_SPACESSTORE, TAG_ID);
|
||||
then(nodesMock).shouldHaveNoMoreInteractions();
|
||||
@@ -594,8 +459,8 @@ public class TagsImplTest
|
||||
|
||||
List<Tag> actual = objectUnderTest.addTags(CONTENT_NODE_ID, tags, parametersMock);
|
||||
|
||||
final List<Tag> expected = List.of(Tag.builder().tag("taga").nodeRef(tagNodeA).count(5L).create(),
|
||||
Tag.builder().tag("tagb").nodeRef(tagNodeB).count(1L).create());
|
||||
final List<Tag> expected = List.of(Tag.builder().tag("taga").nodeRef(tagNodeA).count(5).create(),
|
||||
Tag.builder().tag("tagb").nodeRef(tagNodeB).count(1).create());
|
||||
assertEquals("Unexpected tags returned.", expected, actual);
|
||||
}
|
||||
|
||||
@@ -643,53 +508,6 @@ public class TagsImplTest
|
||||
objectUnderTest.getTags(CONTENT_NODE_ID, parametersMock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangeTag()
|
||||
{
|
||||
Tag suppliedTag = Tag.builder().tag("new-name").create();
|
||||
given(taggingServiceMock.changeTag(STORE_REF_WORKSPACE_SPACESSTORE, TAG_NAME, "new-name")).willReturn(TAG_NODE_REF);
|
||||
|
||||
Tag tag = objectUnderTest.changeTag(STORE_REF_WORKSPACE_SPACESSTORE, TAG_ID, suppliedTag, parametersMock);
|
||||
|
||||
Tag expected = Tag.builder().nodeRef(TAG_NODE_REF).tag("new-name").create();
|
||||
assertEquals("Unexpected return value", expected, tag);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangeTagAndGetCount()
|
||||
{
|
||||
Tag suppliedTag = Tag.builder().tag("new-name").create();
|
||||
given(taggingServiceMock.changeTag(STORE_REF_WORKSPACE_SPACESSTORE, TAG_NAME, "new-name")).willReturn(TAG_NODE_REF);
|
||||
given(parametersMock.getInclude()).willReturn(List.of(PARAM_INCLUDE_COUNT));
|
||||
given(taggingServiceMock.findCountByTagName(STORE_REF_WORKSPACE_SPACESSTORE, TAG_NAME)).willReturn(3L);
|
||||
|
||||
Tag tag = objectUnderTest.changeTag(STORE_REF_WORKSPACE_SPACESSTORE, TAG_ID, suppliedTag, parametersMock);
|
||||
|
||||
Tag expected = Tag.builder().nodeRef(TAG_NODE_REF).tag("new-name").count(3L).create();
|
||||
assertEquals("Unexpected return value", expected, tag);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTag()
|
||||
{
|
||||
Tag tag = objectUnderTest.getTag(STORE_REF_WORKSPACE_SPACESSTORE, TAG_ID, parametersMock);
|
||||
|
||||
Tag expected = Tag.builder().nodeRef(TAG_NODE_REF).tag(TAG_NAME).create();
|
||||
assertEquals("Unexpected tag returned", expected, tag);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTagWithCount()
|
||||
{
|
||||
given(parametersMock.getInclude()).willReturn(List.of(PARAM_INCLUDE_COUNT));
|
||||
given(taggingServiceMock.findCountByTagName(STORE_REF_WORKSPACE_SPACESSTORE, TAG_NAME)).willReturn(0L);
|
||||
|
||||
Tag tag = objectUnderTest.getTag(STORE_REF_WORKSPACE_SPACESSTORE, TAG_ID, parametersMock);
|
||||
|
||||
Tag expected = Tag.builder().nodeRef(TAG_NODE_REF).tag(TAG_NAME).count(0L).create();
|
||||
assertEquals("Unexpected tag returned", expected, tag);
|
||||
}
|
||||
|
||||
private static List<Pair<String, NodeRef>> createTagAndNodeRefPairs(final List<String> tagNames)
|
||||
{
|
||||
return tagNames.stream()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>21.1</version>
|
||||
<version>20.143-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2017 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,10 +26,12 @@
|
||||
|
||||
package org.alfresco.repo.client.config;
|
||||
|
||||
import org.alfresco.repo.admin.SysAdminParams;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.alfresco.util.UrlUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.extensions.surf.util.AbstractLifecycleBean;
|
||||
|
||||
@@ -41,6 +43,7 @@ import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* This class picks up all the loaded properties passed to it and uses a naming
|
||||
@@ -59,25 +62,35 @@ import java.util.concurrent.ConcurrentMap;
|
||||
* for example, <i>sharedLinkBaseUrl</i> and <i>templateAssetsUrl</i> properties, then the following
|
||||
* needs to be put into a properties file.
|
||||
* <ul>
|
||||
* <li>repo.client-app.MyClientName.sharedLinkBaseUrl=http://localhost:8080/MyClientName/s</li>
|
||||
* <li>repo.client-app.MyClientName.templateAssetsUrl=http://localhost:8080/MyClientName/assets</li>
|
||||
* <li>{@code repo.client-app.MyClientName.sharedLinkBaseUrl=http://localhost:8080/MyClientName/s}</li>
|
||||
* <li>{@code repo.client-app.MyClientName.templateAssetsUrl=http://localhost:8080/MyClientName/assets}</li>
|
||||
* </ul>
|
||||
* The default property file is <b>alfresco/client/config/repo-clients-apps.properties</b> which
|
||||
* could be overridden (or add new clients) by <b>alfresco-global</b> properties file.
|
||||
* <p>
|
||||
* <b>Note:</b> The {@literal <clientName>Url} is a special property which can be used as a placeholder.
|
||||
* For example,
|
||||
* <ul>
|
||||
* <li>{@code repo.client-app.MyClientName.MyClientNameUrl=${repoBaseUrl}/entrypoint}</li>
|
||||
* <li>{@code repo.client-app.MyClientName.somePropName=${MyClientNameUrl}/some-page}</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class ClientAppConfig extends AbstractLifecycleBean
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(ClientAppConfig.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ClientAppConfig.class);
|
||||
|
||||
public static final String PREFIX = "repo.client-app.";
|
||||
public static final String PROP_TEMPLATE_ASSETS_URL = "templateAssetsUrl";
|
||||
|
||||
public static final String SHARE_PLACEHOLDER = "${shareUrl}";
|
||||
|
||||
private Properties defaultProperties;
|
||||
private Properties globalProperties;
|
||||
|
||||
private ConcurrentMap<String, ClientApp> clients = new ConcurrentHashMap<>();
|
||||
private final ConcurrentMap<String, ClientApp> clients = new ConcurrentHashMap<>();
|
||||
|
||||
public ClientAppConfig()
|
||||
{
|
||||
@@ -117,6 +130,17 @@ public class ClientAppConfig extends AbstractLifecycleBean
|
||||
return clients.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a client with the given name exists or not.
|
||||
*
|
||||
* @param name the name of the client to check
|
||||
* @return true if the client with the given name exists; false otherwise
|
||||
*/
|
||||
public boolean exists(String name)
|
||||
{
|
||||
return clients.containsKey(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onBootstrap(ApplicationEvent event)
|
||||
{
|
||||
@@ -127,9 +151,9 @@ public class ClientAppConfig extends AbstractLifecycleBean
|
||||
processPropertyKeys(mergedProperties, clientsNames, propsNames);
|
||||
clients.putAll(processClients(clientsNames, propsNames, mergedProperties));
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
logger.debug("All bootstrapped repo clients apps: " + clients);
|
||||
LOGGER.debug("All bootstrapped repo clients apps: " + clients);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +256,7 @@ public class ClientAppConfig extends AbstractLifecycleBean
|
||||
}
|
||||
if (StringUtils.isEmpty(templateAssetsUrl) && config.isEmpty())
|
||||
{
|
||||
logger.warn("Client-app [" + clientName + "] can not be registered as it needs at least one property with a valid value.");
|
||||
LOGGER.warn("Client-app [" + clientName + "] can not be registered as it needs at least one property with a valid value.");
|
||||
continue;
|
||||
}
|
||||
// As the required values are valid, create the client data
|
||||
@@ -275,7 +299,7 @@ public class ClientAppConfig extends AbstractLifecycleBean
|
||||
private void logMalformedPropertyKey(String propName, String reason)
|
||||
{
|
||||
reason = (StringUtils.isBlank(reason)) ? "" : " " + reason;
|
||||
logger.warn("Ignoring client app config (malformed property key) [" + propName + "]." + reason);
|
||||
LOGGER.warn("Ignoring client app config (malformed property key) [" + propName + "]." + reason);
|
||||
}
|
||||
|
||||
private void logMalformedPropertyKey(String propName)
|
||||
@@ -285,9 +309,9 @@ public class ClientAppConfig extends AbstractLifecycleBean
|
||||
|
||||
private void logInvalidPropertyValue(String propName, String propValue)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
if (LOGGER.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Ignoring client app config (invalid value) [" + propValue + "] for the property:" + propName);
|
||||
LOGGER.debug("Ignoring client app config (invalid value) [" + propValue + "] for the property:" + propName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,13 +322,18 @@ public class ClientAppConfig extends AbstractLifecycleBean
|
||||
|
||||
public static class ClientApp
|
||||
{
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ClientApp.class);
|
||||
private final String name;
|
||||
private final String clientUrlPropKey;
|
||||
private final Pattern clientUrlPlaceholderPattern;
|
||||
private final String templateAssetsUrl;
|
||||
private final Map<String, String> properties;
|
||||
|
||||
public ClientApp(String name, String templateAssetsUrl, Map<String, String> properties)
|
||||
{
|
||||
this.name = name;
|
||||
this.clientUrlPropKey = name + "Url"; // E.g. 'workspaceUrl' in 'repo.client-app.workspace.workspaceUrl'
|
||||
this.clientUrlPlaceholderPattern = Pattern.compile("\\$\\{" + clientUrlPropKey + '}'); // E.g. ${workspaceUrl}
|
||||
this.templateAssetsUrl = templateAssetsUrl;
|
||||
this.properties = new HashMap<>(properties);
|
||||
}
|
||||
@@ -314,11 +343,81 @@ public class ClientAppConfig extends AbstractLifecycleBean
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getClientUrlPropKey()
|
||||
{
|
||||
return clientUrlPropKey;
|
||||
}
|
||||
|
||||
public String getClientUrl()
|
||||
{
|
||||
String url = properties.get(getClientUrlPropKey());
|
||||
if (StringUtils.isEmpty(url) && "share".equals(name))
|
||||
{
|
||||
return SHARE_PLACEHOLDER;
|
||||
}
|
||||
LOGGER.info("INSIDE getClientUrl ****--------------------->"+url);
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the client URL that has one of the following defined URL placeholders:
|
||||
* <ul>
|
||||
* <li>{@literal ${repoBaseUrl}}</li>
|
||||
* <li>{@literal ${shareUrl}}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param sysAdminParams SysAdminParams object to retrieve configurable system parameters
|
||||
* @return the resolved property value if applicable
|
||||
*/
|
||||
public String getResolvedClientUrl(SysAdminParams sysAdminParams)
|
||||
{
|
||||
System.out.println("Inside getResolvedClientUrl--------------------->");
|
||||
String resolvedUrl;
|
||||
String clientUrl = getClientUrl();
|
||||
System.out.println("clientUrl is ****--------------------->"+clientUrl);
|
||||
if (!StringUtils.isEmpty(clientUrl) && clientUrl.contains(SHARE_PLACEHOLDER))
|
||||
{
|
||||
resolvedUrl = UrlUtil.replaceShareUrlPlaceholder(clientUrl, sysAdminParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
resolvedUrl = UrlUtil.replaceRepoBaseUrlPlaceholder(clientUrl, sysAdminParams);
|
||||
}
|
||||
|
||||
System.out.println("))))Resolved clientUrl [" + clientUrl + "] to [" + resolvedUrl + "] for the client: " + name);
|
||||
return resolvedUrl;
|
||||
}
|
||||
|
||||
public Pattern getClientUrlPlaceholderPattern()
|
||||
{
|
||||
return clientUrlPlaceholderPattern;
|
||||
}
|
||||
|
||||
public String getTemplateAssetsUrl()
|
||||
{
|
||||
return templateAssetsUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the template assets URL that has the following defined URL placeholder:
|
||||
* <ul>
|
||||
* <li>{@literal ${<clientName>Url}}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param sysAdminParams SysAdminParams object to retrieve configurable system parameters
|
||||
* @return the resolved property value if applicable
|
||||
*/
|
||||
public String getResolvedTemplateAssetsUrl(SysAdminParams sysAdminParams)
|
||||
{
|
||||
String resolvedUrl = UrlUtil.replaceUrlPlaceholder(getClientUrlPlaceholderPattern(), getTemplateAssetsUrl(),
|
||||
getResolvedClientUrl(sysAdminParams));
|
||||
|
||||
LOGGER.debug("Resolved template assets [" + getTemplateAssetsUrl() + "] URL to [" + resolvedUrl
|
||||
+ "] for the client: " + name);
|
||||
|
||||
return UrlUtil.replaceRepoBaseUrlPlaceholder(resolvedUrl, sysAdminParams);
|
||||
}
|
||||
|
||||
public Map<String, String> getProperties()
|
||||
{
|
||||
return Collections.unmodifiableMap(properties);
|
||||
@@ -329,6 +428,27 @@ public class ClientAppConfig extends AbstractLifecycleBean
|
||||
return properties.get(propName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the property that has the following defined URL placeholder:
|
||||
* <ul>
|
||||
* <li>{@literal ${<clientName>Url}}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param propName the property name to search for
|
||||
* @param sysAdminParams SysAdminParams object to retrieve configurable system parameters
|
||||
* @return the resolved property value if applicable
|
||||
*/
|
||||
public String getResolvedProperty(String propName, SysAdminParams sysAdminParams)
|
||||
{
|
||||
String property = getProperty(propName);
|
||||
String resolvedProp = UrlUtil.replaceUrlPlaceholder(getClientUrlPlaceholderPattern(), property,
|
||||
getResolvedClientUrl(sysAdminParams));
|
||||
|
||||
LOGGER.debug("Resolved [" + property + "] URL to [" + resolvedProp + "] for the [" + propName
|
||||
+ "] property of the client: " + name);
|
||||
return resolvedProp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
@@ -356,6 +476,8 @@ public class ClientAppConfig extends AbstractLifecycleBean
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder(250);
|
||||
sb.append("ClientApp [name=").append(name)
|
||||
.append(", clientUrlPropKey=").append(clientUrlPropKey)
|
||||
.append(", clientUrlPlaceholderPattern=").append(clientUrlPlaceholderPattern.pattern())
|
||||
.append(", templateAssetsUrl=").append(templateAssetsUrl)
|
||||
.append(", properties=").append(properties)
|
||||
.append(']');
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* 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
|
||||
@@ -1875,7 +1875,6 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli
|
||||
* @param siteName
|
||||
* @param role
|
||||
* @param runAsUser
|
||||
* @param siteService
|
||||
* @param overrideExisting
|
||||
*/
|
||||
public void addSiteMembership(final String invitee, final String siteName, final String role, final String runAsUser, final boolean overrideExisting)
|
||||
@@ -2111,11 +2110,11 @@ public class InvitationServiceImpl implements InvitationService, NodeServicePoli
|
||||
workflowProps.put(WorkflowModelModeratedInvitation.WF_PROP_RESOURCE_TYPE, resourceType.toString());
|
||||
|
||||
workflowProps.put(WorkflowModelModeratedInvitation.WF_PROP_CLIENT_NAME, clientName);
|
||||
if(clientName != null && clientAppConfig.getClient(clientName) != null)
|
||||
if(clientName != null && clientAppConfig.exists(clientName))
|
||||
{
|
||||
ClientAppConfig.ClientApp client = clientAppConfig.getClient(clientName);
|
||||
workflowProps.put(WorkflowModelModeratedInvitation.WF_TEMPLATE_ASSETS_URL, client.getTemplateAssetsUrl());
|
||||
workflowProps.put(WorkflowModelModeratedInvitation.WF_WORKSPACE_URL, client.getProperty("workspaceUrl"));
|
||||
workflowProps.put(WorkflowModelModeratedInvitation.WF_TEMPLATE_ASSETS_URL, client.getResolvedTemplateAssetsUrl(sysAdminParams));
|
||||
workflowProps.put(WorkflowModelModeratedInvitation.WF_WORKSPACE_URL, client.getResolvedClientUrl(sysAdminParams));
|
||||
}
|
||||
|
||||
// get the moderated workflow
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* 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
|
||||
@@ -72,7 +72,7 @@ public class SendModeratedInviteDelegate extends AbstractInvitationDelegate
|
||||
Map<String, Object> variables = execution.getVariables();
|
||||
String clientName = (String) variables.get(WorkflowModelModeratedInvitation.wfVarClientName);
|
||||
|
||||
if(clientName != null && clientAppConfig.getClient(clientName) != null)
|
||||
if(clientName != null && clientAppConfig.exists(clientName))
|
||||
{
|
||||
ClientAppConfig.ClientApp clientApp = clientAppConfig.getClient(clientName);
|
||||
final String path = clientApp.getProperty("inviteModeratedTemplatePath");
|
||||
|
||||
@@ -23,225 +23,225 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.repo.jscript;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.query.PagingRequest;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.CategoryService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
/**
|
||||
* Support class for finding categories, finding root nodes for categories and creating root categories.
|
||||
*
|
||||
* @author Andy Hind
|
||||
*/
|
||||
public final class Classification extends BaseScopableProcessorExtension
|
||||
{
|
||||
private ServiceRegistry services;
|
||||
|
||||
private StoreRef storeRef;
|
||||
|
||||
/**
|
||||
* Set the default store reference
|
||||
*
|
||||
* @param storeRef the default store reference
|
||||
*/
|
||||
public void setStoreUrl(String storeRef)
|
||||
{
|
||||
this.storeRef = new StoreRef(storeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the service registry
|
||||
*
|
||||
* @param services the service registry
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry services)
|
||||
{
|
||||
this.services = services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all the category nodes in a given classification.
|
||||
*
|
||||
* @param aspect String
|
||||
* @return Scriptable
|
||||
*/
|
||||
public Scriptable getAllCategoryNodes(String aspect)
|
||||
{
|
||||
Object[] cats = buildCategoryNodes(services.getCategoryService().getCategories(
|
||||
storeRef, createQName(aspect), CategoryService.Depth.ANY));
|
||||
return Context.getCurrentContext().newArray(getScope(), cats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the aspects that define a classification.
|
||||
*
|
||||
* @return String[]
|
||||
*/
|
||||
public String[] getAllClassificationAspects()
|
||||
{
|
||||
Collection<QName> aspects = services.getCategoryService().getClassificationAspects();
|
||||
String[] answer = new String[aspects.size()];
|
||||
int i = 0;
|
||||
for (QName qname : aspects)
|
||||
{
|
||||
answer[i++] = qname.toPrefixString(this.services.getNamespaceService());
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a root category in a classification.
|
||||
*
|
||||
* @param aspect String
|
||||
* @param name String
|
||||
*/
|
||||
public CategoryNode createRootCategory(String aspect, String name)
|
||||
{
|
||||
NodeRef categoryNodeRef = services.getCategoryService().createRootCategory(storeRef, createQName(aspect), name);
|
||||
CategoryNode categoryNode = new CategoryNode(categoryNodeRef, this.services, getScope());
|
||||
|
||||
return categoryNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the category node from the category node reference.
|
||||
*
|
||||
* @param categoryRef category node reference
|
||||
* @return {@link CategoryNode} category node
|
||||
*/
|
||||
public CategoryNode getCategory(String categoryRef)
|
||||
{
|
||||
CategoryNode result = null;
|
||||
NodeRef categoryNodeRef = new NodeRef(categoryRef);
|
||||
if (services.getNodeService().exists(categoryNodeRef) == true &&
|
||||
services.getDictionaryService().isSubClass(ContentModel.TYPE_CATEGORY, services.getNodeService().getType(categoryNodeRef)) == true)
|
||||
{
|
||||
result = new CategoryNode(categoryNodeRef, this.services, getScope());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root categories in a classification.
|
||||
*
|
||||
* @param aspect String
|
||||
* @return Scriptable
|
||||
*/
|
||||
public Scriptable getRootCategories(String aspect)
|
||||
{
|
||||
Object[] cats = buildCategoryNodes(services.getCategoryService().getRootCategories(
|
||||
storeRef, createQName(aspect)));
|
||||
return Context.getCurrentContext().newArray(getScope(), cats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ordered, filtered and paged root categories in a classification.
|
||||
*
|
||||
* @param aspect
|
||||
* @param filter
|
||||
* @param maxItems
|
||||
* @param skipCount (offset)
|
||||
* @return
|
||||
*/
|
||||
public Scriptable getRootCategories(String aspect, String filter, int maxItems, int skipCount)
|
||||
{
|
||||
PagingRequest pagingRequest = new PagingRequest(skipCount, maxItems);
|
||||
List<ChildAssociationRef> rootCategories = services.getCategoryService().getRootCategories(storeRef, createQName(aspect), pagingRequest, true, filter).getPage();
|
||||
Object[] cats = buildCategoryNodes(rootCategories);
|
||||
return Context.getCurrentContext().newArray(getScope(), cats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the category usage count.
|
||||
*
|
||||
* @param aspect String
|
||||
* @param maxCount int
|
||||
* @return Scriptable
|
||||
*/
|
||||
public Scriptable getCategoryUsage(String aspect, int maxCount)
|
||||
{
|
||||
List<Pair<NodeRef, Integer>> topCats = services.getCategoryService().getTopCategories(storeRef, createQName(aspect), maxCount);
|
||||
Object[] tags = new Object[topCats.size()];
|
||||
int i = 0;
|
||||
for (Pair<NodeRef, Integer> topCat : topCats)
|
||||
{
|
||||
tags[i++] = new Tag(new CategoryNode(topCat.getFirst(), this.services, getScope()), topCat.getSecond());
|
||||
}
|
||||
|
||||
return Context.getCurrentContext().newArray(getScope(), tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build category nodes.
|
||||
*
|
||||
* @param cars list of associations to category nodes
|
||||
* @return {@link Object}[] array of category nodes
|
||||
*/
|
||||
private Object[] buildCategoryNodes(Collection<ChildAssociationRef> cars)
|
||||
{
|
||||
Object[] categoryNodes = new Object[cars.size()];
|
||||
int i = 0;
|
||||
for (ChildAssociationRef car : cars)
|
||||
{
|
||||
categoryNodes[i++] = new CategoryNode(car.getChildRef(), this.services, getScope());
|
||||
}
|
||||
return categoryNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create QName from string
|
||||
*
|
||||
* @param s QName string value
|
||||
* @return {@link QName} qualified name object
|
||||
*/
|
||||
private QName createQName(String s)
|
||||
{
|
||||
QName qname;
|
||||
if (s.indexOf(QName.NAMESPACE_BEGIN) != -1)
|
||||
{
|
||||
qname = QName.createQName(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
qname = QName.createQName(s, this.services.getNamespaceService());
|
||||
}
|
||||
return qname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag class returned from getCategoryUsage().
|
||||
*/
|
||||
public final class Tag
|
||||
{
|
||||
private CategoryNode categoryNode;
|
||||
private int frequency = 0;
|
||||
|
||||
public Tag(CategoryNode categoryNode, int frequency)
|
||||
{
|
||||
this.categoryNode = categoryNode;
|
||||
this.frequency = frequency;
|
||||
}
|
||||
|
||||
public CategoryNode getCategory()
|
||||
{
|
||||
return categoryNode;
|
||||
}
|
||||
|
||||
public int getFrequency()
|
||||
{
|
||||
return frequency;
|
||||
}
|
||||
}
|
||||
}
|
||||
package org.alfresco.repo.jscript;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.query.PagingRequest;
|
||||
import org.alfresco.service.ServiceRegistry;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.search.CategoryService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.mozilla.javascript.Scriptable;
|
||||
|
||||
/**
|
||||
* Support class for finding categories, finding root nodes for categories and creating root categories.
|
||||
*
|
||||
* @author Andy Hind
|
||||
*/
|
||||
public final class Classification extends BaseScopableProcessorExtension
|
||||
{
|
||||
private ServiceRegistry services;
|
||||
|
||||
private StoreRef storeRef;
|
||||
|
||||
/**
|
||||
* Set the default store reference
|
||||
*
|
||||
* @param storeRef the default store reference
|
||||
*/
|
||||
public void setStoreUrl(String storeRef)
|
||||
{
|
||||
this.storeRef = new StoreRef(storeRef);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the service registry
|
||||
*
|
||||
* @param services the service registry
|
||||
*/
|
||||
public void setServiceRegistry(ServiceRegistry services)
|
||||
{
|
||||
this.services = services;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all the category nodes in a given classification.
|
||||
*
|
||||
* @param aspect String
|
||||
* @return Scriptable
|
||||
*/
|
||||
public Scriptable getAllCategoryNodes(String aspect)
|
||||
{
|
||||
Object[] cats = buildCategoryNodes(services.getCategoryService().getCategories(
|
||||
storeRef, createQName(aspect), CategoryService.Depth.ANY));
|
||||
return Context.getCurrentContext().newArray(getScope(), cats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the aspects that define a classification.
|
||||
*
|
||||
* @return String[]
|
||||
*/
|
||||
public String[] getAllClassificationAspects()
|
||||
{
|
||||
Collection<QName> aspects = services.getCategoryService().getClassificationAspects();
|
||||
String[] answer = new String[aspects.size()];
|
||||
int i = 0;
|
||||
for (QName qname : aspects)
|
||||
{
|
||||
answer[i++] = qname.toPrefixString(this.services.getNamespaceService());
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a root category in a classification.
|
||||
*
|
||||
* @param aspect String
|
||||
* @param name String
|
||||
*/
|
||||
public CategoryNode createRootCategory(String aspect, String name)
|
||||
{
|
||||
NodeRef categoryNodeRef = services.getCategoryService().createRootCategory(storeRef, createQName(aspect), name);
|
||||
CategoryNode categoryNode = new CategoryNode(categoryNodeRef, this.services, getScope());
|
||||
|
||||
return categoryNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the category node from the category node reference.
|
||||
*
|
||||
* @param categoryRef category node reference
|
||||
* @return {@link CategoryNode} category node
|
||||
*/
|
||||
public CategoryNode getCategory(String categoryRef)
|
||||
{
|
||||
CategoryNode result = null;
|
||||
NodeRef categoryNodeRef = new NodeRef(categoryRef);
|
||||
if (services.getNodeService().exists(categoryNodeRef) == true &&
|
||||
services.getDictionaryService().isSubClass(ContentModel.TYPE_CATEGORY, services.getNodeService().getType(categoryNodeRef)) == true)
|
||||
{
|
||||
result = new CategoryNode(categoryNodeRef, this.services, getScope());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root categories in a classification.
|
||||
*
|
||||
* @param aspect String
|
||||
* @return Scriptable
|
||||
*/
|
||||
public Scriptable getRootCategories(String aspect)
|
||||
{
|
||||
Object[] cats = buildCategoryNodes(services.getCategoryService().getRootCategories(
|
||||
storeRef, createQName(aspect)));
|
||||
return Context.getCurrentContext().newArray(getScope(), cats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ordered, filtered and paged root categories in a classification.
|
||||
*
|
||||
* @param aspect
|
||||
* @param filter
|
||||
* @param maxItems
|
||||
* @param skipCount (offset)
|
||||
* @return
|
||||
*/
|
||||
public Scriptable getRootCategories(String aspect, String filter, int maxItems, int skipCount)
|
||||
{
|
||||
PagingRequest pagingRequest = new PagingRequest(skipCount, maxItems);
|
||||
List<ChildAssociationRef> rootCategories = services.getCategoryService().getRootCategories(storeRef, createQName(aspect), pagingRequest, true, filter).getPage();
|
||||
Object[] cats = buildCategoryNodes(rootCategories);
|
||||
return Context.getCurrentContext().newArray(getScope(), cats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the category usage count.
|
||||
*
|
||||
* @param aspect String
|
||||
* @param maxCount int
|
||||
* @return Scriptable
|
||||
*/
|
||||
public Scriptable getCategoryUsage(String aspect, int maxCount)
|
||||
{
|
||||
List<Pair<NodeRef, Integer>> topCats = services.getCategoryService().getTopCategories(storeRef, createQName(aspect), maxCount);
|
||||
Object[] tags = new Object[topCats.size()];
|
||||
int i = 0;
|
||||
for (Pair<NodeRef, Integer> topCat : topCats)
|
||||
{
|
||||
tags[i++] = new Tag(new CategoryNode(topCat.getFirst(), this.services, getScope()), topCat.getSecond());
|
||||
}
|
||||
|
||||
return Context.getCurrentContext().newArray(getScope(), tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build category nodes.
|
||||
*
|
||||
* @param cars list of associations to category nodes
|
||||
* @return {@link Object}[] array of category nodes
|
||||
*/
|
||||
private Object[] buildCategoryNodes(Collection<ChildAssociationRef> cars)
|
||||
{
|
||||
Object[] categoryNodes = new Object[cars.size()];
|
||||
int i = 0;
|
||||
for (ChildAssociationRef car : cars)
|
||||
{
|
||||
categoryNodes[i++] = new CategoryNode(car.getChildRef(), this.services, getScope());
|
||||
}
|
||||
return categoryNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create QName from string
|
||||
*
|
||||
* @param s QName string value
|
||||
* @return {@link QName} qualified name object
|
||||
*/
|
||||
private QName createQName(String s)
|
||||
{
|
||||
QName qname;
|
||||
if (s.indexOf(QName.NAMESPACE_BEGIN) != -1)
|
||||
{
|
||||
qname = QName.createQName(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
qname = QName.createQName(s, this.services.getNamespaceService());
|
||||
}
|
||||
return qname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag class returned from getCategoryUsage().
|
||||
*/
|
||||
public final class Tag
|
||||
{
|
||||
private CategoryNode categoryNode;
|
||||
private int frequency = 0;
|
||||
|
||||
public Tag(CategoryNode categoryNode, int frequency)
|
||||
{
|
||||
this.categoryNode = categoryNode;
|
||||
this.frequency = frequency;
|
||||
}
|
||||
|
||||
public CategoryNode getCategory()
|
||||
{
|
||||
return categoryNode;
|
||||
}
|
||||
|
||||
public int getFrequency()
|
||||
{
|
||||
return frequency;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,23 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2017 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
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* 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%
|
||||
@@ -28,17 +28,15 @@ package org.alfresco.repo.quickshare;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.alfresco.sync.events.types.ActivityEvent;
|
||||
import org.alfresco.sync.events.types.Event;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.QuickShareModel;
|
||||
import org.alfresco.sync.repo.Client;
|
||||
@@ -51,7 +49,6 @@ import org.alfresco.repo.copy.CopyBehaviourCallback;
|
||||
import org.alfresco.repo.copy.CopyDetails;
|
||||
import org.alfresco.repo.copy.CopyServicePolicies;
|
||||
import org.alfresco.repo.copy.DoNothingCopyBehaviourCallback;
|
||||
import org.alfresco.sync.repo.events.EventPreparator;
|
||||
import org.alfresco.sync.repo.events.EventPublisher;
|
||||
import org.alfresco.repo.node.NodeServicePolicies;
|
||||
import org.alfresco.repo.policy.BehaviourFilter;
|
||||
@@ -101,7 +98,6 @@ import org.alfresco.util.EqualsHelper;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.alfresco.util.UrlUtil;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -113,16 +109,16 @@ import org.safehaus.uuid.UUIDGenerator;
|
||||
|
||||
/**
|
||||
* QuickShare Service implementation.
|
||||
*
|
||||
* <p>
|
||||
* In addition to the quick share service, this class also provides a BeforeDeleteNodePolicy and
|
||||
* OnCopyNodePolicy for content with the QuickShare aspect.
|
||||
*
|
||||
* @author Alex Miller, janv, Jamal Kaabi-Mofrad
|
||||
*/
|
||||
public class QuickShareServiceImpl implements QuickShareService,
|
||||
NodeServicePolicies.BeforeDeleteNodePolicy,
|
||||
CopyServicePolicies.OnCopyNodePolicy,
|
||||
NodeServicePolicies.OnRestoreNodePolicy
|
||||
NodeServicePolicies.BeforeDeleteNodePolicy,
|
||||
CopyServicePolicies.OnCopyNodePolicy,
|
||||
NodeServicePolicies.OnRestoreNodePolicy
|
||||
{
|
||||
private static final Log logger = LogFactory.getLog(QuickShareServiceImpl.class);
|
||||
|
||||
@@ -134,7 +130,6 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
private static final String FTL_SENDER_FIRST_NAME = "sender_first_name";
|
||||
private static final String FTL_SENDER_LAST_NAME = "sender_last_name";
|
||||
private static final String FTL_TEMPLATE_ASSETS_URL = "template_assets_url";
|
||||
|
||||
private static final String CONFIG_SHARED_LINK_BASE_URL = "sharedLinkBaseUrl";
|
||||
private static final String DEFAULT_EMAIL_SUBJECT = "quickshare.notifier.email.subject";
|
||||
private static final String EMAIL_TEMPLATE_REF ="alfresco/templates/quickshare-email-templates/quickshare-email.default.template.ftl";
|
||||
@@ -177,9 +172,9 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
*/
|
||||
public void setDictionaryService(DictionaryService dictionaryService)
|
||||
{
|
||||
this.dictionaryService = dictionaryService;
|
||||
this.dictionaryService = dictionaryService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the node service
|
||||
*/
|
||||
@@ -195,15 +190,15 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
{
|
||||
this.permissionService = permissionService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the person service
|
||||
* Set the person service
|
||||
*/
|
||||
public void setPersonService(PersonService personService)
|
||||
public void setPersonService(PersonService personService)
|
||||
{
|
||||
this.personService = personService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the policy component
|
||||
*/
|
||||
@@ -215,11 +210,11 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
/**
|
||||
* Set the tenant service
|
||||
*/
|
||||
public void setTenantService(TenantService tenantService)
|
||||
public void setTenantService(TenantService tenantService)
|
||||
{
|
||||
this.tenantService = tenantService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the thumbnail service
|
||||
*/
|
||||
@@ -227,7 +222,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
{
|
||||
this.thumbnailService = thumbnailService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the eventPublisher
|
||||
*/
|
||||
@@ -394,14 +389,14 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
|
||||
// Register interest in the beforeDeleteNode policy - note: currently for content only !!
|
||||
policyComponent.bindClassBehaviour(
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
|
||||
ContentModel.TYPE_CONTENT,
|
||||
new JavaBehaviour(this, "beforeDeleteNode"));
|
||||
|
||||
QName.createQName(NamespaceService.ALFRESCO_URI, "beforeDeleteNode"),
|
||||
ContentModel.TYPE_CONTENT,
|
||||
new JavaBehaviour(this, "beforeDeleteNode"));
|
||||
|
||||
//Register interest in the onCopyNodePolicy to block copying of quick share metadta
|
||||
policyComponent.bindClassBehaviour(
|
||||
CopyServicePolicies.OnCopyNodePolicy.QNAME,
|
||||
QuickShareModel.ASPECT_QSHARE,
|
||||
CopyServicePolicies.OnCopyNodePolicy.QNAME,
|
||||
QuickShareModel.ASPECT_QSHARE,
|
||||
new JavaBehaviour(this, "getCopyCallback"));
|
||||
|
||||
this.policyComponent.bindClassBehaviour(
|
||||
@@ -424,7 +419,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
|
||||
//Check the node is the correct type
|
||||
final QName typeQName = nodeService.getType(nodeRef);
|
||||
if (isSharable(typeQName) == false)
|
||||
if (!isSharable(typeQName))
|
||||
{
|
||||
throw new InvalidNodeRefException(nodeRef);
|
||||
}
|
||||
@@ -438,7 +433,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
UUID uuid = UUIDGenerator.getInstance().generateRandomBasedUUID();
|
||||
sharedId = Base64.encodeBase64URLSafeString(uuid.toByteArray()); // => 22 chars (eg. q3bEKPeDQvmJYgt4hJxOjw)
|
||||
|
||||
final Map<QName, Serializable> props = new HashMap<QName, Serializable>(2);
|
||||
final Map<QName, Serializable> props = new HashMap<>(2);
|
||||
props.put(QuickShareModel.PROP_QSHARE_SHAREDID, sharedId);
|
||||
props.put(QuickShareModel.PROP_QSHARE_SHAREDBY, AuthenticationUtil.getRunAsUser());
|
||||
|
||||
@@ -448,13 +443,9 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
try
|
||||
{
|
||||
// consumer/contributor should be able to add "shared" aspect (MNT-10366)
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork()
|
||||
{
|
||||
nodeService.addAspect(nodeRef, QuickShareModel.ASPECT_QSHARE, props);
|
||||
return null;
|
||||
}
|
||||
AuthenticationUtil.runAsSystem((RunAsWork<Void>) () -> {
|
||||
nodeService.addAspect(nodeRef, QuickShareModel.ASPECT_QSHARE, props);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
finally
|
||||
@@ -464,27 +455,19 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
|
||||
final NodeRef tenantNodeRef = tenantService.getName(nodeRef);
|
||||
|
||||
TenantUtil.runAsDefaultTenant(new TenantRunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
attributeService.setAttribute(tenantNodeRef, ATTR_KEY_SHAREDIDS_ROOT, sharedId);
|
||||
return null;
|
||||
}
|
||||
TenantUtil.runAsDefaultTenant((TenantRunAsWork<Void>) () -> {
|
||||
attributeService.setAttribute(tenantNodeRef, ATTR_KEY_SHAREDIDS_ROOT, sharedId);
|
||||
return null;
|
||||
});
|
||||
|
||||
final StringBuffer sb = new StringBuffer();
|
||||
sb.append("{").append("\"sharedId\":\"").append(sharedId).append("\"").append("}");
|
||||
String sharedIdStr = "{" + "\"sharedId\":\"" + sharedId + "\"" + "}";
|
||||
|
||||
eventPublisher.publishEvent(new EventPreparator(){
|
||||
@Override
|
||||
public Event prepareEvent(String user, String networkId, String transactionId)
|
||||
{
|
||||
return new ActivityEvent("quickshare", transactionId, networkId, user, nodeRef.getId(),
|
||||
null, typeQName.toString(), Client.asType(ClientType.webclient), sb.toString(),
|
||||
null, null, 0l, null);
|
||||
}
|
||||
});
|
||||
eventPublisher.publishEvent(
|
||||
(user, networkId, transactionId) -> new ActivityEvent("quickshare", transactionId, networkId,
|
||||
user, nodeRef.getId(), null,
|
||||
typeQName.toString(),
|
||||
Client.asType(ClientType.webclient),
|
||||
sharedIdStr, null, null, 0L, null));
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
@@ -523,26 +506,25 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this service enable?
|
||||
* Is this service enable?
|
||||
* @throws QuickShareDisabledException if it isn't.
|
||||
*/
|
||||
private void checkEnabled()
|
||||
{
|
||||
if (enabled == false)
|
||||
if (!enabled)
|
||||
{
|
||||
throw new QuickShareDisabledException("QuickShare is disabled system-wide");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map<String, Object> getMetaData(NodeRef nodeRef)
|
||||
{
|
||||
// TODO This functionality MUST be available when quickshare is also disabled, therefor refactor it out from the quickshare package to a more common package.
|
||||
|
||||
|
||||
Map<QName, Serializable> nodeProps = nodeService.getProperties(nodeRef);
|
||||
ContentData contentData = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
|
||||
|
||||
|
||||
String modifierUserName = (String)nodeProps.get(ContentModel.PROP_MODIFIER);
|
||||
Map<QName, Serializable> personProps = null;
|
||||
if (modifierUserName != null)
|
||||
@@ -557,21 +539,21 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
}
|
||||
catch (NoSuchPersonException nspe)
|
||||
{
|
||||
// absorb this exception - eg. System (or maybe the user has been deleted)
|
||||
// absorb this exception - e.g. System (or maybe the user has been deleted)
|
||||
if (logger.isInfoEnabled())
|
||||
{
|
||||
logger.info("MetaDataGet - no such person: "+modifierUserName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> metadata = new HashMap<String, Object>(8);
|
||||
|
||||
|
||||
Map<String, Object> metadata = new HashMap<>(8);
|
||||
|
||||
metadata.put("nodeRef", nodeRef.toString());
|
||||
metadata.put("name", nodeProps.get(ContentModel.PROP_NAME));
|
||||
metadata.put("title", nodeProps.get(ContentModel.PROP_TITLE));
|
||||
metadata.put("description", nodeProps.get(ContentModel.PROP_DESCRIPTION));
|
||||
|
||||
|
||||
if (contentData != null)
|
||||
{
|
||||
metadata.put("mimetype", contentData.getMimetype());
|
||||
@@ -581,17 +563,17 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
{
|
||||
metadata.put("size", 0L);
|
||||
}
|
||||
|
||||
|
||||
metadata.put("modified", nodeProps.get(ContentModel.PROP_MODIFIED));
|
||||
|
||||
|
||||
if (personProps != null)
|
||||
{
|
||||
metadata.put("modifierFirstName", personProps.get(ContentModel.PROP_FIRSTNAME));
|
||||
metadata.put("modifierLastName", personProps.get(ContentModel.PROP_LASTNAME));
|
||||
}
|
||||
|
||||
|
||||
// thumbnail defs for this nodeRef
|
||||
List<String> thumbnailDefs = new ArrayList<String>(7);
|
||||
List<String> thumbnailDefs = new ArrayList<>(7);
|
||||
if (contentData != null)
|
||||
{
|
||||
// Note: thumbnail defs only appear in this list if they can produce a thumbnail for the content
|
||||
@@ -604,18 +586,18 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
}
|
||||
}
|
||||
metadata.put("thumbnailDefinitions", thumbnailDefs);
|
||||
|
||||
|
||||
// thumbnail instances for this nodeRef
|
||||
List<NodeRef> thumbnailRefs = thumbnailService.getThumbnails(nodeRef, ContentModel.PROP_CONTENT, null, null);
|
||||
List<String> thumbnailNames = new ArrayList<String>(thumbnailRefs.size());
|
||||
List<String> thumbnailNames = new ArrayList<>(thumbnailRefs.size());
|
||||
for (NodeRef thumbnailRef : thumbnailRefs)
|
||||
{
|
||||
thumbnailNames.add((String)nodeService.getProperty(thumbnailRef, ContentModel.PROP_NAME));
|
||||
}
|
||||
metadata.put("thumbnailNames", thumbnailNames);
|
||||
|
||||
metadata.put("lastThumbnailModificationData", (List<String>)nodeProps.get(ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA));
|
||||
|
||||
|
||||
metadata.put("lastThumbnailModificationData", nodeProps.get(ContentModel.PROP_LAST_THUMBNAIL_MODIFICATION_DATA));
|
||||
|
||||
if (nodeProps.containsKey(QuickShareModel.PROP_QSHARE_SHAREDID))
|
||||
{
|
||||
metadata.put("sharedId", nodeProps.get(QuickShareModel.PROP_QSHARE_SHAREDID));
|
||||
@@ -629,7 +611,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
metadata.put("sharable", sharable);
|
||||
}
|
||||
|
||||
Map<String, Object> model = new HashMap<String, Object>(2);
|
||||
Map<String, Object> model = new HashMap<>(2);
|
||||
model.put("item", metadata);
|
||||
return model;
|
||||
}
|
||||
@@ -637,13 +619,8 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
@Override
|
||||
public Pair<String, NodeRef> getTenantNodeRefFromSharedId(final String sharedId)
|
||||
{
|
||||
NodeRef nodeRef = TenantUtil.runAsDefaultTenant(new TenantRunAsWork<NodeRef>()
|
||||
{
|
||||
public NodeRef doWork() throws Exception
|
||||
{
|
||||
return (NodeRef) attributeService.getAttribute(ATTR_KEY_SHAREDIDS_ROOT, sharedId);
|
||||
}
|
||||
});
|
||||
NodeRef nodeRef = TenantUtil.runAsDefaultTenant(
|
||||
() -> (NodeRef) attributeService.getAttribute(ATTR_KEY_SHAREDIDS_ROOT, sharedId));
|
||||
|
||||
if (nodeRef == null)
|
||||
{
|
||||
@@ -659,7 +636,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
sp.setQuery(query);
|
||||
sp.addStore(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
|
||||
|
||||
List<NodeRef> nodeRefs = null;
|
||||
List<NodeRef> nodeRefs;
|
||||
ResultSet results = null;
|
||||
try
|
||||
{
|
||||
@@ -697,23 +674,19 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(sharedId);
|
||||
final String tenantDomain = pair.getFirst();
|
||||
final NodeRef nodeRef = pair.getSecond();
|
||||
|
||||
Map<String, Object> model = TenantUtil.runAsSystemTenant(new TenantRunAsWork<Map<String, Object>>()
|
||||
{
|
||||
public Map<String, Object> doWork() throws Exception
|
||||
{
|
||||
checkQuickShareNode(nodeRef);
|
||||
|
||||
return getMetaData(nodeRef);
|
||||
}
|
||||
|
||||
Map<String, Object> model = TenantUtil.runAsSystemTenant(() -> {
|
||||
checkQuickShareNode(nodeRef);
|
||||
|
||||
return getMetaData(nodeRef);
|
||||
}, tenantDomain);
|
||||
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("QuickShare - retrieved metadata: "+sharedId+" ["+nodeRef+"]["+model+"]");
|
||||
}
|
||||
//model.put("nodeRef", nodeRef)
|
||||
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -729,44 +702,40 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
// note: will remove "share" even if node is only being archived (ie. moved to trash) => a subsequent restore will *not* restore the "share"
|
||||
public void beforeDeleteNode(final NodeRef beforeDeleteNodeRef)
|
||||
{
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
AuthenticationUtil.runAsSystem((RunAsWork<Void>) () -> {
|
||||
String sharedId = (String)nodeService.getProperty(beforeDeleteNodeRef, QuickShareModel.PROP_QSHARE_SHAREDID);
|
||||
if (sharedId != null)
|
||||
{
|
||||
String sharedId = (String)nodeService.getProperty(beforeDeleteNodeRef, QuickShareModel.PROP_QSHARE_SHAREDID);
|
||||
if (sharedId != null)
|
||||
try
|
||||
{
|
||||
try
|
||||
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(sharedId);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
final String tenantDomain = pair.getFirst();
|
||||
final NodeRef nodeRef = pair.getSecond();
|
||||
|
||||
// note: deleted nodeRef might not match, eg. for upload new version -> checkin -> delete working copy
|
||||
if (nodeRef.equals(beforeDeleteNodeRef))
|
||||
{
|
||||
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(sharedId);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
final String tenantDomain = pair.getFirst();
|
||||
final NodeRef nodeRef = pair.getSecond();
|
||||
|
||||
// note: deleted nodeRef might not match, eg. for upload new version -> checkin -> delete working copy
|
||||
if (nodeRef.equals(beforeDeleteNodeRef))
|
||||
// Disable audit to preserve modifier and modified date
|
||||
behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
try
|
||||
{
|
||||
// Disable audit to preserve modifier and modified date
|
||||
behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
try
|
||||
{
|
||||
nodeService.removeAspect(nodeRef, QuickShareModel.ASPECT_QSHARE);
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
}
|
||||
removeSharedId(sharedId);
|
||||
nodeService.removeAspect(nodeRef, QuickShareModel.ASPECT_QSHARE);
|
||||
}
|
||||
}
|
||||
catch (InvalidSharedIdException ex)
|
||||
{
|
||||
logger.warn("Couldn't find shareId, " + sharedId + ", attributes for node " + beforeDeleteNodeRef);
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
}
|
||||
removeSharedId(sharedId);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
catch (InvalidSharedIdException ex)
|
||||
{
|
||||
logger.warn("Couldn't find shareId, " + sharedId + ", attributes for node " + beforeDeleteNodeRef);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -778,37 +747,29 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
public void onRestoreNode(ChildAssociationRef childAssocRef)
|
||||
{
|
||||
final NodeRef childNodeRef = childAssocRef.getChildRef();
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
AuthenticationUtil.runAsSystem((RunAsWork<Void>) () -> {
|
||||
if (nodeService.hasAspect(childNodeRef, QuickShareModel.ASPECT_QSHARE))
|
||||
{
|
||||
if (nodeService.hasAspect(childNodeRef, QuickShareModel.ASPECT_QSHARE))
|
||||
// Disable audit to preserve modifier and modified date
|
||||
behaviourFilter.disableBehaviour(childNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
try
|
||||
{
|
||||
// Disable audit to preserve modifier and modified date
|
||||
behaviourFilter.disableBehaviour(childNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
try
|
||||
{
|
||||
nodeService.removeAspect(childNodeRef, QuickShareModel.ASPECT_QSHARE);
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableBehaviour(childNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
}
|
||||
nodeService.removeAspect(childNodeRef, QuickShareModel.ASPECT_QSHARE);
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableBehaviour(childNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private void removeSharedId(final String sharedId)
|
||||
{
|
||||
TenantUtil.runAsDefaultTenant(new TenantRunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
attributeService.removeAttribute(ATTR_KEY_SHAREDIDS_ROOT, sharedId);
|
||||
return null;
|
||||
}
|
||||
TenantUtil.runAsDefaultTenant((TenantRunAsWork<Void>) () -> {
|
||||
attributeService.removeAttribute(ATTR_KEY_SHAREDIDS_ROOT, sharedId);
|
||||
return null;
|
||||
});
|
||||
|
||||
try
|
||||
@@ -832,40 +793,36 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(sharedId);
|
||||
final String tenantDomain = pair.getFirst();
|
||||
final NodeRef nodeRef = pair.getSecond();
|
||||
|
||||
TenantUtil.runAsSystemTenant(new TenantRunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
QName typeQName = nodeService.getType(nodeRef);
|
||||
if (! isSharable(typeQName))
|
||||
{
|
||||
throw new InvalidNodeRefException(nodeRef);
|
||||
}
|
||||
|
||||
String nodeSharedId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDID);
|
||||
|
||||
if (! EqualsHelper.nullSafeEquals(nodeSharedId, sharedId))
|
||||
{
|
||||
logger.warn("SharedId mismatch: expected="+sharedId+",actual="+nodeSharedId);
|
||||
}
|
||||
|
||||
// Disable audit to preserve modifier and modified date
|
||||
// And not to create version
|
||||
// see MNT-15654
|
||||
behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
try
|
||||
{
|
||||
nodeService.removeAspect(nodeRef, QuickShareModel.ASPECT_QSHARE);
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
}
|
||||
return null;
|
||||
TenantUtil.runAsSystemTenant((TenantRunAsWork<Void>) () -> {
|
||||
QName typeQName = nodeService.getType(nodeRef);
|
||||
if (! isSharable(typeQName))
|
||||
{
|
||||
throw new InvalidNodeRefException(nodeRef);
|
||||
}
|
||||
|
||||
String nodeSharedId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDID);
|
||||
|
||||
if (! EqualsHelper.nullSafeEquals(nodeSharedId, sharedId))
|
||||
{
|
||||
logger.warn("SharedId mismatch: expected="+sharedId+",actual="+nodeSharedId);
|
||||
}
|
||||
|
||||
// Disable audit to preserve modifier and modified date
|
||||
// And not to create version
|
||||
// see MNT-15654
|
||||
behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
try
|
||||
{
|
||||
nodeService.removeAspect(nodeRef, QuickShareModel.ASPECT_QSHARE);
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
}
|
||||
return null;
|
||||
}, tenantDomain);
|
||||
|
||||
|
||||
removeSharedId(sharedId);
|
||||
|
||||
if (logger.isInfoEnabled())
|
||||
@@ -891,23 +848,19 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
Pair<String, NodeRef> pair = getTenantNodeRefFromSharedId(sharedId);
|
||||
final String tenantDomain = pair.getFirst();
|
||||
final NodeRef nodeRef = pair.getSecond();
|
||||
|
||||
return TenantUtil.runAsTenant(new TenantRunAsWork<Boolean>()
|
||||
{
|
||||
public Boolean doWork() throws Exception
|
||||
|
||||
return TenantUtil.runAsTenant(() -> {
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
checkQuickShareNode(nodeRef);
|
||||
return permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.ALLOWED;
|
||||
}
|
||||
catch (AccessDeniedException ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
checkQuickShareNode(nodeRef);
|
||||
return permissionService.hasPermission(nodeRef, PermissionService.READ) == AccessStatus.ALLOWED;
|
||||
}
|
||||
catch (AccessDeniedException ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}, tenantDomain);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -934,18 +887,18 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
Map<String, Serializable> templateModel = new HashMap<>(6);
|
||||
templateModel.put(FTL_SENDER_FIRST_NAME, senderFirstName);
|
||||
templateModel.put(FTL_SENDER_LAST_NAME, senderLastName);
|
||||
final String sharedNodeUrl = getUrl(clientApp.getProperty(CONFIG_SHARED_LINK_BASE_URL), CONFIG_SHARED_LINK_BASE_URL)
|
||||
+ '/' + emailRequest.getSharedId();
|
||||
String resolvedUrl = getUrl(clientApp.getResolvedProperty(CONFIG_SHARED_LINK_BASE_URL, sysAdminParams), CONFIG_SHARED_LINK_BASE_URL);
|
||||
final String sharedNodeUrl = resolvedUrl + '/' + emailRequest.getSharedId();
|
||||
|
||||
templateModel.put(FTL_SHARED_NODE_URL, sharedNodeUrl);
|
||||
templateModel.put(FTL_SHARED_NODE_NAME, emailRequest.getSharedNodeName());
|
||||
templateModel.put(FTL_SENDER_MESSAGE, emailRequest.getSenderMessage());
|
||||
final String templateAssetsUrl = getUrl(clientApp.getTemplateAssetsUrl(), ClientAppConfig.PROP_TEMPLATE_ASSETS_URL);
|
||||
final String templateAssetsUrl = getUrl(clientApp.getResolvedTemplateAssetsUrl(sysAdminParams), ClientAppConfig.PROP_TEMPLATE_ASSETS_URL);
|
||||
templateModel.put(FTL_TEMPLATE_ASSETS_URL, templateAssetsUrl);
|
||||
|
||||
// Set the email details
|
||||
Map<String, Serializable> actionParams = new HashMap<>();
|
||||
// Email sender. By default the current-user's email address will not be used to send this mail.
|
||||
// Email sender. By default, the current-user's email address will not be used to send this mail.
|
||||
// However, current-user's first and lastname will be used as the personal name.
|
||||
actionParams.put(MailActionExecuter.PARAM_FROM, this.defaultEmailSender);
|
||||
actionParams.put(MailActionExecuter.PARAM_FROM_PERSONAL_NAME, senderFullName);
|
||||
@@ -981,21 +934,21 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
|
||||
String currentUser = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
String siteName = getSiteName(nodeRef);
|
||||
boolean isSharedByCurrentUser = currentUser.equals(sharedByUserId);
|
||||
boolean isSharedByCurrentUser = Objects.equals(currentUser, sharedByUserId);
|
||||
|
||||
if (siteName != null)
|
||||
{
|
||||
// node belongs to a site - current user must be a manager or collaborator or someone who shared the link
|
||||
String role = siteService.getMembersRole(siteName, currentUser);
|
||||
if (isSharedByCurrentUser || (role != null && (role.equals(SiteModel.SITE_MANAGER) || role.equals(SiteModel.SITE_COLLABORATOR)))
|
||||
|| (authorityService.isAdminAuthority(currentUser)))
|
||||
|| (authorityService.isAdminAuthority(currentUser)))
|
||||
{
|
||||
canDeleteSharedLink = true;
|
||||
}
|
||||
}
|
||||
else if (isSharedByCurrentUser || (authorityService.isAdminAuthority(currentUser)))
|
||||
{
|
||||
// node does not belongs to a site - current user must be the person who shared the link or an admin
|
||||
// node does not belong to a site - current user must be the person who shared the link or an admin
|
||||
canDeleteSharedLink = true;
|
||||
}
|
||||
|
||||
@@ -1015,11 +968,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
while (parent != null && !nodeService.getType(parent).equals(SiteModel.TYPE_SITE))
|
||||
{
|
||||
// check that we can read parent name
|
||||
if (permissionService.hasReadPermission(parent) == AccessStatus.ALLOWED)
|
||||
{
|
||||
String parentName = (String) nodeService.getProperty(parent,ContentModel.PROP_NAME);
|
||||
}
|
||||
else
|
||||
if (!(permissionService.hasReadPermission(parent) == AccessStatus.ALLOWED))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@@ -1048,8 +997,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
{
|
||||
url = url.substring(0, url.length() - 1);
|
||||
}
|
||||
// Replace '${shareUrl} placeholder if it does exist.
|
||||
return UrlUtil.replaceShareUrlPlaceholder(url, sysAdminParams);
|
||||
return url;
|
||||
}
|
||||
|
||||
private <T> T getDefaultIfNull(T defaultValue, T newValue)
|
||||
@@ -1134,7 +1082,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
{
|
||||
if (toEmails != null)
|
||||
{
|
||||
this.toEmails = Collections.unmodifiableSet(new HashSet<>(toEmails));
|
||||
this.toEmails = Set.copyOf(toEmails);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1239,7 +1187,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
}
|
||||
|
||||
final NodeRef expiryActionNodeRef = getQuickShareLinkExpiryActionNode(sharedId);
|
||||
// If an expiry action already exists for the specified shared Id, first remove it, before creating a new one.
|
||||
// If an expiry action already exists for the specified sharedId, first remove it, before creating a new one.
|
||||
if (expiryActionNodeRef != null)
|
||||
{
|
||||
deleteQuickShareLinkExpiryAction(expiryActionNodeRef);
|
||||
@@ -1247,11 +1195,11 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
|
||||
// Create the expiry action
|
||||
final QuickShareLinkExpiryAction expiryAction = new QuickShareLinkExpiryActionImpl(java.util.UUID.randomUUID().toString(), sharedId,
|
||||
"QuickShare link expiry action");
|
||||
"QuickShare link expiry action");
|
||||
// Create the persisted schedule
|
||||
final ScheduledPersistedAction schedule = scheduledPersistedActionService.createSchedule(expiryAction);
|
||||
|
||||
// first set the scheduledAction so we can set the other information
|
||||
// first set the scheduledAction, so we can set the other information
|
||||
expiryAction.setSchedule(schedule);
|
||||
expiryAction.setScheduleStart(expiryDate);
|
||||
|
||||
@@ -1273,7 +1221,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Quick share link expiry action is created for sharedId[" + sharedId + "] and it's scheduled to be executed on: "
|
||||
+ expiryDate);
|
||||
+ expiryDate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1298,7 +1246,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
// Delete the expiry action and its related persisted schedule
|
||||
deleteQuickShareLinkExpiryActionImpl(linkExpiryAction);
|
||||
|
||||
// As the method is called directly (ie. not via unshareContent method which removes the aspect properties),
|
||||
// As the method is called directly (i.e. not via unshareContent method which removes the aspect properties),
|
||||
// then we have to remove the 'expiryDate' property as well.
|
||||
if (sharedNodeRef != null && nodeService.getProperty(sharedNodeRef, QuickShareModel.PROP_QSHARE_EXPIRY_DATE) != null)
|
||||
{
|
||||
@@ -1342,7 +1290,7 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
quickShareLinkExpiryActionPersister.deleteQuickShareLinkExpiryAction(linkExpiryAction);
|
||||
}
|
||||
|
||||
private QuickShareLinkExpiryAction attachSchedule(QuickShareLinkExpiryAction quickShareLinkExpiryAction)
|
||||
private void attachSchedule(QuickShareLinkExpiryAction quickShareLinkExpiryAction)
|
||||
{
|
||||
if (quickShareLinkExpiryAction.getSchedule() == null)
|
||||
{
|
||||
@@ -1350,7 +1298,6 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
quickShareLinkExpiryAction.setSchedule(schedule);
|
||||
|
||||
}
|
||||
return quickShareLinkExpiryAction;
|
||||
}
|
||||
|
||||
private NodeRef getQuickShareLinkExpiryActionNode(String sharedId)
|
||||
@@ -1381,54 +1328,53 @@ public class QuickShareServiceImpl implements QuickShareService,
|
||||
private enum ExpiryDatePeriod
|
||||
{
|
||||
DAYS
|
||||
{
|
||||
@Override
|
||||
int getDuration(DateTime now, DateTime expiryDate)
|
||||
{
|
||||
Interval interval = new Interval(now.withSecondOfMinute(0).withMillisOfSecond(0), expiryDate);
|
||||
return interval.toPeriod(PeriodType.days()).getDays();
|
||||
}
|
||||
{
|
||||
@Override
|
||||
int getDuration(DateTime now, DateTime expiryDate)
|
||||
{
|
||||
Interval interval = new Interval(now.withSecondOfMinute(0).withMillisOfSecond(0), expiryDate);
|
||||
return interval.toPeriod(PeriodType.days()).getDays();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getMessage()
|
||||
{
|
||||
return "day (24 hours)";
|
||||
}
|
||||
},
|
||||
@Override
|
||||
String getMessage()
|
||||
{
|
||||
return "day (24 hours)";
|
||||
}
|
||||
},
|
||||
HOURS
|
||||
{
|
||||
@Override
|
||||
int getDuration(DateTime now, DateTime expiryDate)
|
||||
{
|
||||
Interval interval = new Interval(now.withSecondOfMinute(0).withMillisOfSecond(0), expiryDate);
|
||||
return interval.toPeriod(PeriodType.hours()).getHours();
|
||||
}
|
||||
{
|
||||
@Override
|
||||
int getDuration(DateTime now, DateTime expiryDate)
|
||||
{
|
||||
Interval interval = new Interval(now.withSecondOfMinute(0).withMillisOfSecond(0), expiryDate);
|
||||
return interval.toPeriod(PeriodType.hours()).getHours();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getMessage()
|
||||
{
|
||||
return "hour";
|
||||
}
|
||||
},
|
||||
@Override
|
||||
String getMessage()
|
||||
{
|
||||
return "hour";
|
||||
}
|
||||
},
|
||||
MINUTES
|
||||
{
|
||||
@Override
|
||||
public int getDuration(DateTime now, DateTime expiryDate)
|
||||
{
|
||||
Interval interval = new Interval(now.withMillisOfSecond(0), expiryDate);
|
||||
return interval.toPeriod(PeriodType.minutes()).getMinutes();
|
||||
}
|
||||
{
|
||||
@Override
|
||||
public int getDuration(DateTime now, DateTime expiryDate)
|
||||
{
|
||||
Interval interval = new Interval(now.withMillisOfSecond(0), expiryDate);
|
||||
return interval.toPeriod(PeriodType.minutes()).getMinutes();
|
||||
}
|
||||
|
||||
@Override
|
||||
String getMessage()
|
||||
{
|
||||
return "minute";
|
||||
}
|
||||
};
|
||||
@Override
|
||||
String getMessage()
|
||||
{
|
||||
return "minute";
|
||||
}
|
||||
};
|
||||
|
||||
abstract int getDuration(DateTime now, DateTime expiryDate);
|
||||
|
||||
abstract String getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -514,11 +514,15 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
NodeRef renditionNode = getRenditionNode(sourceNodeRef, renditionName);
|
||||
boolean createRenditionNode = renditionNode == null;
|
||||
boolean sourceHasAspectRenditioned = nodeService.hasAspect(sourceNodeRef, RenditionModel.ASPECT_RENDITIONED);
|
||||
boolean sourceChanges = !sourceHasAspectRenditioned || createRenditionNode || transformInputStream == null;
|
||||
try
|
||||
{
|
||||
ruleService.disableRuleType(RuleType.UPDATE);
|
||||
behaviourFilter.disableBehaviour(sourceNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
behaviourFilter.disableBehaviour(sourceNodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
if (sourceChanges)
|
||||
{
|
||||
ruleService.disableRuleType(RuleType.UPDATE);
|
||||
behaviourFilter.disableBehaviour(sourceNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
behaviourFilter.disableBehaviour(sourceNodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
}
|
||||
|
||||
// If they do not exist create the rendition association and the rendition node.
|
||||
if (createRenditionNode)
|
||||
@@ -588,9 +592,12 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
|
||||
}
|
||||
finally
|
||||
{
|
||||
behaviourFilter.enableBehaviour(sourceNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
behaviourFilter.enableBehaviour(sourceNodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
ruleService.enableRuleType(RuleType.UPDATE);
|
||||
if (sourceChanges)
|
||||
{
|
||||
behaviourFilter.enableBehaviour(sourceNodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
behaviourFilter.enableBehaviour(sourceNodeRef, ContentModel.ASPECT_VERSIONABLE);
|
||||
ruleService.enableRuleType(RuleType.UPDATE);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}, false, true));
|
||||
|
||||
@@ -414,7 +414,34 @@ public abstract class AbstractCategoryServiceImpl implements CategoryService
|
||||
int count = 0;
|
||||
boolean moreItems = false;
|
||||
|
||||
final Function<NodeRef, Collection<ChildAssociationRef>> childNodesSupplier = getNodeRefCollectionFunction(sortByName, exactNamesFilter, alikeNamesFilter, skipCount, maxItems);
|
||||
final Function<NodeRef, Collection<ChildAssociationRef>> childNodesSupplier = (nodeRef) -> {
|
||||
final Set<ChildAssociationRef> childNodes = new HashSet<>();
|
||||
if (CollectionUtils.isEmpty(exactNamesFilter) && CollectionUtils.isEmpty(alikeNamesFilter))
|
||||
{
|
||||
// lookup in DB without filtering
|
||||
childNodes.addAll(nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_SUBCATEGORIES, RegexQNamePattern.MATCH_ALL));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CollectionUtils.isNotEmpty(exactNamesFilter))
|
||||
{
|
||||
// lookup in DB filtering by name
|
||||
childNodes.addAll(nodeService.getChildrenByName(nodeRef, ContentModel.ASSOC_SUBCATEGORIES, exactNamesFilter));
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(alikeNamesFilter))
|
||||
{
|
||||
// lookup using search engin filtering by name
|
||||
childNodes.addAll(getChildren(nodeRef, Mode.SUB_CATEGORIES, Depth.IMMEDIATE, sortByName, alikeNamesFilter, skipCount + maxItems + 1));
|
||||
}
|
||||
}
|
||||
|
||||
Stream<ChildAssociationRef> childNodesStream = childNodes.stream();
|
||||
if (sortByName)
|
||||
{
|
||||
childNodesStream = childNodesStream.sorted(Comparator.comparing(tag -> tag.getQName().getLocalName()));
|
||||
}
|
||||
return childNodesStream.collect(Collectors.toList());
|
||||
};
|
||||
|
||||
OUTER_LOOP: for(NodeRef nodeRef : nodeRefs)
|
||||
{
|
||||
@@ -441,55 +468,6 @@ public abstract class AbstractCategoryServiceImpl implements CategoryService
|
||||
return new ListBackedPagingResults<>(associations, moreItems);
|
||||
}
|
||||
|
||||
public Collection<ChildAssociationRef> getRootCategories(StoreRef storeRef, QName aspectName, Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter)
|
||||
{
|
||||
final Set<NodeRef> nodeRefs = getClassificationNodes(storeRef, aspectName);
|
||||
final List<ChildAssociationRef> associations = new LinkedList<>();
|
||||
|
||||
final Function<NodeRef, Collection<ChildAssociationRef>> childNodesSupplier = getNodeRefCollectionFunction(false, exactNamesFilter, alikeNamesFilter, 0, 10000);
|
||||
|
||||
for (NodeRef nodeRef : nodeRefs)
|
||||
{
|
||||
Collection<ChildAssociationRef> children = childNodesSupplier.apply(nodeRef);
|
||||
associations.addAll(children);
|
||||
}
|
||||
|
||||
return associations;
|
||||
}
|
||||
|
||||
private Function<NodeRef, Collection<ChildAssociationRef>> getNodeRefCollectionFunction(boolean sortByName, Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter, int skipCount, int maxItems)
|
||||
{
|
||||
final Function<NodeRef, Collection<ChildAssociationRef>> childNodesSupplier = (nodeRef) -> {
|
||||
final Set<ChildAssociationRef> childNodes = new HashSet<>();
|
||||
if (CollectionUtils.isEmpty(exactNamesFilter) && CollectionUtils.isEmpty(alikeNamesFilter))
|
||||
{
|
||||
// lookup in DB without filtering
|
||||
childNodes.addAll(nodeService.getChildAssocs(nodeRef, ContentModel.ASSOC_SUBCATEGORIES, RegexQNamePattern.MATCH_ALL));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CollectionUtils.isNotEmpty(exactNamesFilter))
|
||||
{
|
||||
// lookup in DB filtering by name
|
||||
childNodes.addAll(nodeService.getChildrenByName(nodeRef, ContentModel.ASSOC_SUBCATEGORIES, exactNamesFilter));
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(alikeNamesFilter))
|
||||
{
|
||||
// lookup using search engine filtering by name
|
||||
childNodes.addAll(getChildren(nodeRef, Mode.SUB_CATEGORIES, Depth.IMMEDIATE, sortByName, alikeNamesFilter, skipCount + maxItems + 1));
|
||||
}
|
||||
}
|
||||
|
||||
Stream<ChildAssociationRef> childNodesStream = childNodes.stream();
|
||||
if (sortByName)
|
||||
{
|
||||
childNodesStream = childNodesStream.sorted(Comparator.comparing(tag -> tag.getQName().getLocalName()));
|
||||
}
|
||||
return childNodesStream.collect(Collectors.toList());
|
||||
};
|
||||
return childNodesSupplier;
|
||||
}
|
||||
|
||||
public Collection<ChildAssociationRef> getRootCategories(StoreRef storeRef, QName aspectName)
|
||||
{
|
||||
return getRootCategories(storeRef, aspectName, null);
|
||||
|
||||
@@ -32,13 +32,11 @@ import org.alfresco.repo.client.config.ClientAppNotFoundException;
|
||||
import org.alfresco.repo.security.authentication.ResetPasswordServiceImpl.ResetPasswordDetails;
|
||||
|
||||
/**
|
||||
* @deprecated from 7.1.0
|
||||
* Reset password service.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ResetPasswordService
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -2,23 +2,23 @@
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2017 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
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* 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%
|
||||
@@ -61,8 +61,8 @@ import org.alfresco.util.ParameterCheck;
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.alfresco.util.UrlUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
import org.springframework.extensions.webscripts.WebScriptException;
|
||||
|
||||
@@ -74,17 +74,15 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @deprecated from 7.1.0
|
||||
* *
|
||||
*
|
||||
* Reset password implementation based on workflow.
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
@Deprecated
|
||||
public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
{
|
||||
private static final Log LOGGER = LogFactory.getLog(ResetPasswordServiceImpl.class);
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ResetPasswordServiceImpl.class);
|
||||
|
||||
private static final String TIMER_END = "PT1H";
|
||||
private static final String WORKFLOW_DESCRIPTION_KEY = "resetpasswordwf_resetpassword.resetpassword.workflow.description";
|
||||
@@ -196,6 +194,7 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
ParameterCheck.mandatoryString("clientName", clientName);
|
||||
|
||||
String userEmail = validateUserAndGetEmail(userId);
|
||||
validateClient(clientName);
|
||||
|
||||
// Get the (latest) workflow definition for reset-password.
|
||||
WorkflowDefinition wfDefinition = workflowService.getDefinitionByName(WorkflowModelResetPassword.WORKFLOW_DEFINITION_NAME);
|
||||
@@ -342,8 +341,9 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
}
|
||||
else if (!username.equals(userId))
|
||||
{
|
||||
throw new InvalidResetPasswordWorkflowException("The given user id [" + userId + "] does not match the person's user id [" + username
|
||||
+ "] who requested the password reset.");
|
||||
throw new InvalidResetPasswordWorkflowException(
|
||||
"The given user id [" + userId + "] does not match the person's user id [" + username
|
||||
+ "] who requested the password reset.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,12 +352,16 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
{
|
||||
ParameterCheck.mandatoryString("clientName", clientName);
|
||||
|
||||
ClientApp clientApp = clientAppConfig.getClient(clientName);
|
||||
if (clientApp == null)
|
||||
validateClient(clientName);
|
||||
return clientAppConfig.getClient(clientName);
|
||||
}
|
||||
|
||||
private void validateClient(String clientName)
|
||||
{
|
||||
if (!clientAppConfig.exists(clientName))
|
||||
{
|
||||
throw new ClientAppNotFoundException("Client was not found [" + clientName + "]");
|
||||
}
|
||||
return clientApp;
|
||||
}
|
||||
|
||||
|
||||
@@ -383,9 +387,9 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
.setUserName(userName)
|
||||
.setUserEmail(toEmail)
|
||||
.setTemplatePath(templatePath)
|
||||
.setTemplateAssetsUrl(clientApp.getTemplateAssetsUrl())
|
||||
.setEmailSubject(emailSubject)
|
||||
.setTemplateModel(emailTemplateModel);
|
||||
.setTemplateModel(emailTemplateModel)
|
||||
.setClientApp(clientApp);
|
||||
|
||||
sendEmail(emailRequest);
|
||||
}
|
||||
@@ -400,7 +404,7 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
final String userName = (String) execution.getVariable(WorkflowModelResetPassword.WF_PROP_USERNAME_ACTIVITI);
|
||||
|
||||
// But we cannot get the password from the execution as we have intentionally not stored the password there.
|
||||
// Instead we recover the password from the specific task in which it was set.
|
||||
// Instead, we recover the password from the specific task in which it was set.
|
||||
List<Task> activitiTasks = activitiTaskService.createTaskQuery().taskDefinitionKey(WorkflowModelResetPassword.TASK_RESET_PASSWORD)
|
||||
.processInstanceId(execution.getProcessInstanceId()).list();
|
||||
if (activitiTasks.size() != 1)
|
||||
@@ -448,9 +452,9 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
.setUserName(userName)
|
||||
.setUserEmail(userEmail)
|
||||
.setTemplatePath(templatePath)
|
||||
.setTemplateAssetsUrl(clientApp.getTemplateAssetsUrl())
|
||||
.setEmailSubject(emailSubject)
|
||||
.setTemplateModel(emailTemplateModel);
|
||||
.setTemplateModel(emailTemplateModel)
|
||||
.setClientApp(clientApp);
|
||||
|
||||
sendEmail(emailRequest);
|
||||
}
|
||||
@@ -460,7 +464,9 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
// Prepare the email
|
||||
Map<String, Serializable> templateModel = new HashMap<>();
|
||||
// Replace '${shareUrl}' placeholder if it does exist.
|
||||
final String templateAssetsUrl = getUrl(emailRequest.getTemplateAssetsUrl(), ClientAppConfig.PROP_TEMPLATE_ASSETS_URL);
|
||||
ClientApp clientApp = emailRequest.getClientApp();
|
||||
final String templateAssetsUrl = getUrl(clientApp.getResolvedTemplateAssetsUrl(sysAdminParams),
|
||||
ClientAppConfig.PROP_TEMPLATE_ASSETS_URL, clientApp.getName());
|
||||
templateModel.put(FTL_TEMPLATE_ASSETS_URL, templateAssetsUrl);
|
||||
if (emailRequest.getTemplateModel() != null)
|
||||
{
|
||||
@@ -489,11 +495,11 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
actionService.executeAction(mailAction, null, false, sendEmailAsynchronously);
|
||||
}
|
||||
|
||||
private String getUrl(String url, String propName)
|
||||
private String getUrl(String url, String propName, String clientName)
|
||||
{
|
||||
if (url == null)
|
||||
if (StringUtils.isEmpty(url))
|
||||
{
|
||||
LOGGER.warn("The url for the property [" + propName + "] is not configured.");
|
||||
LOGGER.warn("The url for the property [" + propName + "] is not configured for the client: " + clientName);
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -501,7 +507,7 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
{
|
||||
url = url.substring(0, url.length() - 1);
|
||||
}
|
||||
return UrlUtil.replaceShareUrlPlaceholder(url, sysAdminParams);
|
||||
return url;
|
||||
}
|
||||
|
||||
protected String getResetPasswordEmailTemplate(ClientApp clientApp)
|
||||
@@ -521,22 +527,23 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(100);
|
||||
|
||||
String pageUrl = clientApp.getProperty("resetPasswordPageUrl");
|
||||
String pageUrl = clientApp.getResolvedProperty("resetPasswordPageUrl", sysAdminParams);
|
||||
if (StringUtils.isEmpty(pageUrl))
|
||||
{
|
||||
sb.append(UrlUtil.getShareUrl(sysAdminParams));
|
||||
LOGGER.warn("'resetPasswordPageUrl' property is not set for the client [" + clientApp.getName() + "]. The default base url of Share will be used [" + sb + "]");
|
||||
|
||||
LOGGER.warn("'resetPasswordPageUrl' property is not set for the client [" + clientApp.getName()
|
||||
+ "]. The default base url of Share will be used [" + sb.toString() + "]");
|
||||
}
|
||||
else
|
||||
{
|
||||
// We pass an empty string as we know that the pageUrl is not null
|
||||
sb.append(getUrl(pageUrl, ""));
|
||||
sb.append(getUrl(pageUrl, "resetPasswordPageUrl", clientApp.getName()));
|
||||
}
|
||||
|
||||
sb.append("?key=").append(key)
|
||||
.append("&id=").append(BPMEngineRegistry.createGlobalId(ActivitiConstants.ENGINE_ID, id));
|
||||
sb.append("?key=")
|
||||
.append(key)
|
||||
.append("&id=")
|
||||
.append(BPMEngineRegistry.createGlobalId(ActivitiConstants.ENGINE_ID, id));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
@@ -616,10 +623,10 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
private String userEmail;
|
||||
private String fromEmail;
|
||||
private String templatePath;
|
||||
private String templateAssetsUrl;
|
||||
private Map<String, Serializable> templateModel;
|
||||
private String emailSubject;
|
||||
private boolean ignoreSendFailure = true;
|
||||
private ClientApp clientApp;
|
||||
|
||||
public String getUserName()
|
||||
{
|
||||
@@ -665,17 +672,6 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTemplateAssetsUrl()
|
||||
{
|
||||
return templateAssetsUrl;
|
||||
}
|
||||
|
||||
public ResetPasswordEmailDetails setTemplateAssetsUrl(String templateAssetsUrl)
|
||||
{
|
||||
this.templateAssetsUrl = templateAssetsUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, Serializable> getTemplateModel()
|
||||
{
|
||||
return templateModel;
|
||||
@@ -709,18 +705,29 @@ public class ResetPasswordServiceImpl implements ResetPasswordService
|
||||
return this;
|
||||
}
|
||||
|
||||
public ClientApp getClientApp()
|
||||
{
|
||||
return clientApp;
|
||||
}
|
||||
|
||||
public ResetPasswordEmailDetails setClientApp(ClientApp clientApp)
|
||||
{
|
||||
this.clientApp = clientApp;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
final StringBuilder sb = new StringBuilder(250);
|
||||
final StringBuilder sb = new StringBuilder(300);
|
||||
sb.append("ResetPasswordEmailDetails [userName=").append(userName)
|
||||
.append(", userEmail=").append(userEmail)
|
||||
.append(", fromEmail=").append(fromEmail)
|
||||
.append(", templatePath=").append(templatePath)
|
||||
.append(", templateAssetsUrl=").append(templateAssetsUrl)
|
||||
.append(", templateModel=").append(templateModel)
|
||||
.append(", emailSubject=").append(emailSubject)
|
||||
.append(", ignoreSendFailure=").append(ignoreSendFailure)
|
||||
.append(", clientApp=").append(clientApp)
|
||||
.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -357,13 +357,8 @@ public class IdentityServiceFacadeFactoryBean implements FactoryBean<IdentitySer
|
||||
|
||||
private ClientRegistration.Builder createBuilder(OIDCProviderMetadata metadata)
|
||||
{
|
||||
final String authUri = Optional.of(metadata)
|
||||
.map(OIDCProviderMetadata::getAuthorizationEndpointURI)
|
||||
.map(URI::toASCIIString)
|
||||
.orElse(null);
|
||||
return ClientRegistration
|
||||
.withRegistrationId("ids")
|
||||
.authorizationUri(authUri)
|
||||
.tokenUri(metadata.getTokenEndpointURI().toASCIIString())
|
||||
.jwkSetUri(metadata.getJWKSetURI().toASCIIString())
|
||||
.issuerUri(config.getIssuerUrl())
|
||||
|
||||
@@ -1605,6 +1605,8 @@ public class LDAPUserRegistry implements UserRegistry, LDAPNameResolver, Initial
|
||||
this.userSearchCtls = new SearchControls();
|
||||
this.userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||
this.userSearchCtls.setReturningAttributes(LDAPUserRegistry.this.userKeys.getFirst());
|
||||
// MNT-14001 fix, set search limit to ensure that server will not return more search results then provided by paged result control
|
||||
this.userSearchCtls.setCountLimit(LDAPUserRegistry.this.queryBatchSize > 0 ? LDAPUserRegistry.this.queryBatchSize : 0);
|
||||
|
||||
this.next = fetchNext();
|
||||
}
|
||||
|
||||
@@ -27,10 +27,8 @@ package org.alfresco.repo.tagging;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
|
||||
import static org.alfresco.model.ContentModel.ASPECT_WORKING_COPY;
|
||||
import static org.alfresco.model.ContentModel.ASSOC_SUBCATEGORIES;
|
||||
import static org.alfresco.model.ContentModel.PROP_NAME;
|
||||
import static org.alfresco.service.cmr.search.SearchService.LANGUAGE_LUCENE;
|
||||
import static org.alfresco.service.namespace.NamespaceService.CONTENT_MODEL_1_0_URI;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
@@ -46,16 +44,12 @@ import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.query.EmptyPagingResults;
|
||||
@@ -65,7 +59,6 @@ import org.alfresco.repo.audit.AuditComponent;
|
||||
import org.alfresco.repo.coci.CheckOutCheckInServicePolicies.OnCheckOut;
|
||||
import org.alfresco.repo.copy.CopyServicePolicies.BeforeCopyPolicy;
|
||||
import org.alfresco.repo.copy.CopyServicePolicies.OnCopyCompletePolicy;
|
||||
import org.alfresco.repo.domain.query.QueryException;
|
||||
import org.alfresco.repo.event2.EventGenerator;
|
||||
import org.alfresco.repo.node.NodeServicePolicies.BeforeDeleteNodePolicy;
|
||||
import org.alfresco.repo.node.NodeServicePolicies.OnCreateNodePolicy;
|
||||
@@ -126,7 +119,7 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
|
||||
private static Log logger = LogFactory.getLog(TaggingServiceImpl.class);
|
||||
|
||||
private static Collator collator = Collator.getInstance();
|
||||
private static Collator collator = Collator.getInstance();
|
||||
|
||||
private NodeService nodeService;
|
||||
private NodeService nodeServiceInternal;
|
||||
@@ -143,9 +136,6 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
private static final String TAG_DETAILS_DELIMITER = "|";
|
||||
/** Next tag delimiter */
|
||||
private static final String NEXT_TAG_DELIMITER = "\n";
|
||||
/** Parameters Include count */
|
||||
private static final String PARAM_INCLUDE_COUNT = "count";
|
||||
|
||||
|
||||
private static Set<String> FORBIDDEN_TAGS_SEQUENCES = new HashSet<String>(Arrays.asList(new String[] {NEXT_TAG_DELIMITER, TAG_DETAILS_DELIMITER}));
|
||||
|
||||
@@ -343,7 +333,7 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
public void beforeDeleteNode(NodeRef nodeRef)
|
||||
{
|
||||
if (this.nodeService.exists(nodeRef) == true &&
|
||||
this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TAGGABLE) == true && !this.nodeService.hasAspect(nodeRef, ASPECT_WORKING_COPY))
|
||||
this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TAGGABLE) == true && !this.nodeService.hasAspect(nodeRef, ContentModel.ASPECT_WORKING_COPY))
|
||||
{
|
||||
updateAllScopeTags(nodeRef, Boolean.FALSE);
|
||||
}
|
||||
@@ -502,8 +492,8 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
{
|
||||
// Lower the case of the tag
|
||||
tag = tag.toLowerCase();
|
||||
|
||||
return getTagNodeRef(storeRef, tag, true);
|
||||
|
||||
return getTagNodeRef(storeRef, tag, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -532,33 +522,33 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
|
||||
public NodeRef changeTag(StoreRef storeRef, String existingTag, String newTag)
|
||||
{
|
||||
if (existingTag == null)
|
||||
{
|
||||
throw new TaggingException("Existing tag cannot be null");
|
||||
}
|
||||
if (existingTag == null)
|
||||
{
|
||||
throw new TaggingException("Existing tag cannot be null");
|
||||
}
|
||||
|
||||
if (newTag == null || StringUtils.isBlank(newTag))
|
||||
{
|
||||
throw new TaggingException("New tag cannot be blank");
|
||||
}
|
||||
|
||||
if (newTag == null || StringUtils.isBlank(newTag))
|
||||
{
|
||||
throw new TaggingException("New tag cannot be blank");
|
||||
}
|
||||
existingTag = existingTag.toLowerCase();
|
||||
newTag = newTag.toLowerCase();
|
||||
|
||||
existingTag = existingTag.toLowerCase();
|
||||
newTag = newTag.toLowerCase();
|
||||
|
||||
if (existingTag.equals(newTag))
|
||||
{
|
||||
throw new TaggingException("New and existing tags are the same");
|
||||
}
|
||||
|
||||
if (getTagNodeRef(storeRef, existingTag) == null)
|
||||
{
|
||||
throw new NonExistentTagException("Tag " + existingTag + " not found");
|
||||
}
|
||||
|
||||
if (getTagNodeRef(storeRef, newTag) != null)
|
||||
{
|
||||
throw new TagExistsException("Tag " + newTag + " already exists");
|
||||
}
|
||||
if (existingTag.equals(newTag))
|
||||
{
|
||||
throw new TaggingException("New and existing tags are the same");
|
||||
}
|
||||
|
||||
if (getTagNodeRef(storeRef, existingTag) == null)
|
||||
{
|
||||
throw new NonExistentTagException("Tag " + existingTag + " not found");
|
||||
}
|
||||
|
||||
if (getTagNodeRef(storeRef, newTag) != null)
|
||||
{
|
||||
throw new TagExistsException("Tag " + newTag + " already exists");
|
||||
}
|
||||
|
||||
NodeRef tagNodeRef = getTagNodeRef(storeRef, existingTag);
|
||||
nodeService.setProperty(tagNodeRef, PROP_NAME, newTag);
|
||||
@@ -688,21 +678,6 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Long> calculateCount(StoreRef storeRef)
|
||||
{
|
||||
List<Pair<String, Integer>> tagsByCount = findTaggedNodesAndCountByTagName(storeRef);
|
||||
Map<String, Long> tagsByCountMap = new HashMap<>();
|
||||
if (tagsByCount != null)
|
||||
{
|
||||
for (Pair<String, Integer> tagByCountElem : tagsByCount)
|
||||
{
|
||||
tagsByCountMap.put(tagByCountElem.getFirst(), Long.valueOf(tagByCountElem.getSecond()));
|
||||
}
|
||||
}
|
||||
return tagsByCountMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see TaggingService#hasTag(NodeRef, String)
|
||||
*/
|
||||
@@ -718,12 +693,12 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
@SuppressWarnings("unchecked")
|
||||
public NodeRef addTag(final NodeRef nodeRef, final String tagName)
|
||||
{
|
||||
NodeRef newTagNodeRef = null;
|
||||
|
||||
if(tagName == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Must provide a non-null tag");
|
||||
}
|
||||
NodeRef newTagNodeRef = null;
|
||||
|
||||
if(tagName == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Must provide a non-null tag");
|
||||
}
|
||||
|
||||
updateTagBehaviour.disable();
|
||||
createTagBehaviour.disable();
|
||||
@@ -773,7 +748,7 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
*/
|
||||
public List<Pair<String, NodeRef>> addTags(NodeRef nodeRef, List<String> tags)
|
||||
{
|
||||
List<Pair<String, NodeRef>> ret = new ArrayList<Pair<String, NodeRef>>();
|
||||
List<Pair<String, NodeRef>> ret = new ArrayList<Pair<String, NodeRef>>();
|
||||
for (String tag : tags)
|
||||
{
|
||||
NodeRef tagNodeRef = addTag(nodeRef, tag);
|
||||
@@ -894,36 +869,36 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
int skipCount = pagingRequest.getSkipCount();
|
||||
int maxItems = pagingRequest.getMaxItems();
|
||||
int end = maxItems == Integer.MAX_VALUE ? totalItems : skipCount + maxItems;
|
||||
int size = (maxItems == Integer.MAX_VALUE ? totalItems : maxItems);
|
||||
int size = (maxItems == Integer.MAX_VALUE ? totalItems : maxItems);
|
||||
|
||||
final List<Pair<NodeRef, String>> sortedTags = new ArrayList<Pair<NodeRef, String>>(size);
|
||||
// grab all tags and sort (assume fairly low number of tags)
|
||||
for(NodeRef tagNode : currentTagNodes)
|
||||
{
|
||||
// grab all tags and sort (assume fairly low number of tags)
|
||||
for(NodeRef tagNode : currentTagNodes)
|
||||
{
|
||||
String tag = (String)this.nodeService.getProperty(tagNode, PROP_NAME);
|
||||
sortedTags.add(new Pair<NodeRef, String>(tagNode, tag));
|
||||
}
|
||||
}
|
||||
Collections.sort(sortedTags, new Comparator<Pair<NodeRef, String>>()
|
||||
{
|
||||
@Override
|
||||
public int compare(Pair<NodeRef, String> o1, Pair<NodeRef, String> o2)
|
||||
{
|
||||
String tag1 = o1.getSecond();
|
||||
String tag2 = o2.getSecond();
|
||||
return collator.compare(tag1, tag2);
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public int compare(Pair<NodeRef, String> o1, Pair<NodeRef, String> o2)
|
||||
{
|
||||
String tag1 = o1.getSecond();
|
||||
String tag2 = o2.getSecond();
|
||||
return collator.compare(tag1, tag2);
|
||||
}
|
||||
});
|
||||
|
||||
final List<Pair<NodeRef, String>> result = new ArrayList<Pair<NodeRef, String>>(size);
|
||||
Iterator<Pair<NodeRef, String>> it = sortedTags.iterator();
|
||||
Iterator<Pair<NodeRef, String>> it = sortedTags.iterator();
|
||||
for(int count = 0; count < end && it.hasNext(); count++)
|
||||
{
|
||||
Pair<NodeRef, String> tagPair = it.next();
|
||||
Pair<NodeRef, String> tagPair = it.next();
|
||||
|
||||
if(count < skipCount)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(count < skipCount)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result.add(tagPair);
|
||||
}
|
||||
@@ -932,30 +907,30 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
|
||||
return new PagingResults<Pair<NodeRef, String>>()
|
||||
{
|
||||
@Override
|
||||
public List<Pair<NodeRef, String>> getPage()
|
||||
{
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
public List<Pair<NodeRef, String>> getPage()
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreItems()
|
||||
{
|
||||
return hasMoreItems;
|
||||
}
|
||||
@Override
|
||||
public boolean hasMoreItems()
|
||||
{
|
||||
return hasMoreItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Integer, Integer> getTotalResultCount()
|
||||
{
|
||||
Integer total = Integer.valueOf(totalItems);
|
||||
return new Pair<Integer, Integer>(total, total);
|
||||
}
|
||||
@Override
|
||||
public Pair<Integer, Integer> getTotalResultCount()
|
||||
{
|
||||
Integer total = Integer.valueOf(totalItems);
|
||||
return new Pair<Integer, Integer>(total, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryExecutionId()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public String getQueryExecutionId()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -979,83 +954,7 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
exactNamesFilter, alikeNamesFilter);
|
||||
|
||||
return mapPagingResult(rootCategories,
|
||||
(childAssociation) -> new Pair<>(childAssociation.getChildRef(), childAssociation.getQName().getLocalName()));
|
||||
}
|
||||
|
||||
public Map<NodeRef, Long> getTags(StoreRef storeRef, List<String> parameterIncludes, Pair<String, Boolean> sorting, Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter)
|
||||
{
|
||||
ParameterCheck.mandatory("storeRef", storeRef);
|
||||
Collection<ChildAssociationRef> rootCategories = categoryService.getRootCategories(storeRef, ContentModel.ASPECT_TAGGABLE, exactNamesFilter, alikeNamesFilter);
|
||||
|
||||
Map<String, Long> tagsMap = new TreeMap<>();
|
||||
for (ChildAssociationRef childAssociation : rootCategories)
|
||||
{
|
||||
tagsMap.put(childAssociation.getQName().getLocalName(), 0L);
|
||||
}
|
||||
|
||||
Map<String, Long> tagsByCountMap = new HashMap<>();
|
||||
|
||||
if(parameterIncludes.contains(PARAM_INCLUDE_COUNT))
|
||||
{
|
||||
tagsByCountMap = calculateCount(storeRef);
|
||||
|
||||
for (Map.Entry<String, Long> entry : tagsMap.entrySet()) {
|
||||
entry.setValue(Optional.ofNullable(tagsByCountMap.get(entry.getKey())).orElse(0L));
|
||||
}
|
||||
}
|
||||
|
||||
//check if we should sort results. Can only sort by one parameter, default order is ascending
|
||||
if (sorting != null)
|
||||
{
|
||||
if (sorting.getFirst().equals("tag"))
|
||||
{
|
||||
if (!sorting.getSecond())
|
||||
{
|
||||
Stream<Map.Entry<String,Long>> sortedTags =
|
||||
tagsMap.entrySet().stream()
|
||||
.sorted(Collections.reverseOrder(Map.Entry.comparingByKey()));
|
||||
tagsMap = sortedTags.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream<Map.Entry<String,Long>> sortedTags =
|
||||
tagsMap.entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByKey());
|
||||
tagsMap = sortedTags.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
}
|
||||
}
|
||||
else if (sorting.getFirst().equals(PARAM_INCLUDE_COUNT))
|
||||
{
|
||||
if (tagsByCountMap.isEmpty())
|
||||
{
|
||||
throw new IllegalArgumentException("Tag count should be included when ordering by count");
|
||||
}
|
||||
|
||||
if (!sorting.getSecond())
|
||||
{
|
||||
Stream<Map.Entry<String, Long>> sortedTags =
|
||||
tagsMap.entrySet().stream()
|
||||
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()));
|
||||
tagsMap = sortedTags.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream<Map.Entry<String,Long>> sortedTags =
|
||||
tagsMap.entrySet().stream()
|
||||
.sorted(Map.Entry.comparingByValue());
|
||||
tagsMap = sortedTags.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<NodeRef, Long> tagNodeRefMap = new LinkedHashMap<>();
|
||||
|
||||
for (Map.Entry<String, Long> entry : tagsMap.entrySet())
|
||||
{
|
||||
tagNodeRefMap.put(getTagNodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, entry.getKey()), entry.getValue());
|
||||
}
|
||||
|
||||
return tagNodeRefMap;
|
||||
(childAssociation) -> new Pair<>(childAssociation.getChildRef(), childAssociation.getQName().getLocalName()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1289,15 +1188,15 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
*/
|
||||
private void getTagScopes(final NodeRef nodeRef, List<NodeRef> tagScopes, boolean firstOnly)
|
||||
{
|
||||
Boolean hasAspect = AuthenticationUtil.runAs(new RunAsWork<Boolean>()
|
||||
{
|
||||
@Override
|
||||
public Boolean doWork() throws Exception
|
||||
{
|
||||
return new Boolean(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TAGSCOPE));
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
Boolean hasAspect = AuthenticationUtil.runAs(new RunAsWork<Boolean>()
|
||||
{
|
||||
@Override
|
||||
public Boolean doWork() throws Exception
|
||||
{
|
||||
return new Boolean(nodeService.hasAspect(nodeRef, ContentModel.ASPECT_TAGSCOPE));
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
if (Boolean.TRUE.equals(hasAspect) == true)
|
||||
{
|
||||
tagScopes.add(nodeRef);
|
||||
@@ -1308,23 +1207,23 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
}
|
||||
|
||||
NodeRef parent = AuthenticationUtil.runAs(new RunAsWork<NodeRef>()
|
||||
{
|
||||
@Override
|
||||
public NodeRef doWork() throws Exception
|
||||
{
|
||||
NodeRef result = null;
|
||||
ChildAssociationRef assoc = nodeService.getPrimaryParent(nodeRef);
|
||||
if (assoc != null)
|
||||
{
|
||||
result = assoc.getParentRef();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
{
|
||||
@Override
|
||||
public NodeRef doWork() throws Exception
|
||||
{
|
||||
NodeRef result = null;
|
||||
ChildAssociationRef assoc = nodeService.getPrimaryParent(nodeRef);
|
||||
if (assoc != null)
|
||||
{
|
||||
result = assoc.getParentRef();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}, AuthenticationUtil.getSystemUserName());
|
||||
|
||||
if (parent != null)
|
||||
{
|
||||
getTagScopes(parent, tagScopes, firstOnly);
|
||||
getTagScopes(parent, tagScopes, firstOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1342,7 +1241,7 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
// Do the search for nodes
|
||||
resultSet = this.searchService.query(
|
||||
storeRef,
|
||||
LANGUAGE_LUCENE,
|
||||
SearchService.LANGUAGE_LUCENE,
|
||||
"+PATH:\"/cm:taggable/cm:" + ISO9075.encode(tag) + "/member\"");
|
||||
List<NodeRef> nodeRefs = resultSet.getNodeRefs();
|
||||
return nodeRefs;
|
||||
@@ -1371,7 +1270,7 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
// Do query
|
||||
resultSet = this.searchService.query(
|
||||
storeRef,
|
||||
LANGUAGE_LUCENE,
|
||||
SearchService.LANGUAGE_LUCENE,
|
||||
"+PATH:\"" + pathString + "//*\" +PATH:\"/cm:taggable/cm:" + ISO9075.encode(tag) + "/member\"");
|
||||
List<NodeRef> nodeRefs = resultSet.getNodeRefs();
|
||||
return nodeRefs;
|
||||
@@ -1639,7 +1538,7 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
public void afterCheckOut(NodeRef workingCopy)
|
||||
{
|
||||
if (this.nodeService.exists(workingCopy) == true && this.nodeService.hasAspect(workingCopy, ContentModel.ASPECT_TAGGABLE) == true
|
||||
&& this.nodeService.hasAspect(workingCopy, ASPECT_WORKING_COPY))
|
||||
&& this.nodeService.hasAspect(workingCopy, ContentModel.ASPECT_WORKING_COPY))
|
||||
{
|
||||
updateAllScopeTags(workingCopy, Boolean.FALSE);
|
||||
}
|
||||
@@ -1651,10 +1550,10 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
@Override
|
||||
public List<Pair<String, Integer>> findTaggedNodesAndCountByTagName(StoreRef storeRef)
|
||||
{
|
||||
String queryTaggeble = "ASPECT:\"" + ContentModel.ASPECT_TAGGABLE + "\"" + "-ASPECT:\"" + ASPECT_WORKING_COPY + "\"";
|
||||
String queryTaggeble = "ASPECT:\"" + ContentModel.ASPECT_TAGGABLE + "\"" + "-ASPECT:\"" + ContentModel.ASPECT_WORKING_COPY + "\"";
|
||||
SearchParameters sp = new SearchParameters();
|
||||
sp.setQuery(queryTaggeble);
|
||||
sp.setLanguage(LANGUAGE_LUCENE);
|
||||
sp.setLanguage(SearchService.LANGUAGE_LUCENE);
|
||||
sp.addStore(storeRef);
|
||||
sp.addFieldFacet(new FieldFacet("TAG"));
|
||||
|
||||
@@ -1674,32 +1573,6 @@ public class TaggingServiceImpl implements TaggingService,
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public long findCountByTagName(StoreRef storeRef, String name)
|
||||
{
|
||||
String query = "TAG:\"" + name + "\"" + "-ASPECT:\"" + ASPECT_WORKING_COPY + "\"";
|
||||
SearchParameters sp = new SearchParameters();
|
||||
sp.setQuery(query);
|
||||
sp.setLanguage(LANGUAGE_LUCENE);
|
||||
sp.addStore(storeRef);
|
||||
|
||||
ResultSet resultSet = null;
|
||||
try
|
||||
{
|
||||
// Do the search for nodes
|
||||
resultSet = this.searchService.query(sp);
|
||||
return resultSet.getNumberFound();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (resultSet != null)
|
||||
{
|
||||
resultSet.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Experimental
|
||||
@Override
|
||||
public List<Pair<String, NodeRef>> createTags(final StoreRef storeRef, final List<String> tagNames)
|
||||
|
||||
@@ -29,12 +29,10 @@ package org.alfresco.repo.workflow;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* @deprecated from 7.1.0
|
||||
*
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
* @since 5.2.1
|
||||
*/
|
||||
@Deprecated
|
||||
public interface WorkflowModelResetPassword
|
||||
{
|
||||
// namespace
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
package org.alfresco.service.cmr.search;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -151,21 +150,11 @@ public interface CategoryService
|
||||
*/
|
||||
@Auditable(parameters = {"storeRef", "aspectName", "pagingRequest", "sortByName", "exactNamesFilter", "alikeNamesFilter"})
|
||||
default PagingResults<ChildAssociationRef> getRootCategories(StoreRef storeRef, QName aspectName, PagingRequest pagingRequest, boolean sortByName,
|
||||
Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter)
|
||||
Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter)
|
||||
{
|
||||
return new EmptyPagingResults<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of the root categories for an aspect/classification supporting multiple name filters.
|
||||
*/
|
||||
@Auditable(parameters = {"storeRef", "aspectName", "exactNamesFilter", "alikeNamesFilter"})
|
||||
default Collection<ChildAssociationRef> getRootCategories(StoreRef storeRef, QName aspectName, Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the root categories for an aspect/classification with names that start with filter
|
||||
*
|
||||
|
||||
@@ -28,7 +28,6 @@ package org.alfresco.service.cmr.tagging;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.api.AlfrescoPublicApi;
|
||||
import org.alfresco.query.EmptyPagingResults;
|
||||
@@ -95,18 +94,6 @@ public interface TaggingService
|
||||
{
|
||||
return new EmptyPagingResults<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map of tag NodeRefs and their respective usage count filtered by name and sorted by tag name or count
|
||||
*
|
||||
* @param storeRef
|
||||
* @param parameterIncludes
|
||||
* @param sorting
|
||||
* @param exactNamesFilter
|
||||
* @param alikeNamesFilter
|
||||
* @return
|
||||
*/
|
||||
Map<NodeRef, Long> getTags(StoreRef storeRef, List<String>parameterIncludes, Pair<String, Boolean> sorting, Collection<String> exactNamesFilter, Collection<String> alikeNamesFilter);
|
||||
|
||||
/**
|
||||
* Get all the tags currently available that match the provided filter.
|
||||
@@ -340,7 +327,8 @@ public interface TaggingService
|
||||
*/
|
||||
@NotAuditable
|
||||
Pair<List<String>, Integer> getPagedTags(StoreRef storeRef, String filter, int fromTag, int pageSize);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get tagged nodes and count of nodes group by tag name
|
||||
*
|
||||
@@ -350,16 +338,6 @@ public interface TaggingService
|
||||
@NotAuditable
|
||||
List<Pair<String, Integer>> findTaggedNodesAndCountByTagName(StoreRef storeRef);
|
||||
|
||||
/**
|
||||
* Get the number of tagged nodes for a given tag.
|
||||
*
|
||||
* @param storeRef The store containing the nodes.
|
||||
* @param name The name of the tag.
|
||||
* @return The number of nodes tagged with the specified tag.
|
||||
*/
|
||||
@NotAuditable
|
||||
long findCountByTagName(StoreRef storeRef, String name);
|
||||
|
||||
/**
|
||||
* Creates orphan tags. Tag names case will be lowered.
|
||||
*
|
||||
@@ -374,13 +352,6 @@ public interface TaggingService
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param storeRef
|
||||
* @return a map with each tag name and its usage count
|
||||
*/
|
||||
Map<String, Long> calculateCount(StoreRef storeRef);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,23 +2,23 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2017 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
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* 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%
|
||||
@@ -32,43 +32,62 @@ import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Alfresco URL related utility functions.
|
||||
*
|
||||
*
|
||||
* @since 3.5
|
||||
*/
|
||||
public class UrlUtil
|
||||
{
|
||||
// ${shareUrl} placeholder
|
||||
public static final Pattern PATTERN = Pattern.compile("\\$\\{shareUrl\\}");
|
||||
|
||||
// ${alfrescoUrl} placeholder
|
||||
public static final Pattern REPO_PATTERN = Pattern.compile("\\$\\{alfrescoUrl\\}");
|
||||
|
||||
// ${repoBaseUrl} placeholder
|
||||
public static final Pattern REPO_BASE_PATTERN = Pattern.compile("\\$\\{repoBaseUrl\\}");
|
||||
|
||||
/**
|
||||
* Builds up the Url to Alfresco based on the settings in the
|
||||
* {@link SysAdminParams}.
|
||||
* @return Alfresco Url such as https://col.ab.or.ate/alfresco/
|
||||
* or http://localhost:8080/alfresco/
|
||||
* Builds up the Url to Alfresco root url based on the settings in the
|
||||
* {@link SysAdminParams}.
|
||||
* @return Alfresco base Url such as {@code https://col.ab.or.ate}
|
||||
* or {@code http://localhost:8080}
|
||||
*/
|
||||
public static String getAlfrescoBaseUrl(SysAdminParams sysAdminParams)
|
||||
{
|
||||
return buildBaseUrl(
|
||||
sysAdminParams.getAlfrescoProtocol(),
|
||||
sysAdminParams.getAlfrescoHost(),
|
||||
sysAdminParams.getAlfrescoPort());
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds up the Url to Alfresco context based on the settings in the
|
||||
* {@link SysAdminParams}.
|
||||
* @return Alfresco Url such as {@code https://col.ab.or.ate/alfresco}
|
||||
* or {@code http://localhost:8080/alfresco}
|
||||
*/
|
||||
public static String getAlfrescoUrl(SysAdminParams sysAdminParams)
|
||||
{
|
||||
return buildUrl(
|
||||
sysAdminParams.getAlfrescoProtocol(),
|
||||
sysAdminParams.getAlfrescoHost(),
|
||||
sysAdminParams.getAlfrescoPort(),
|
||||
sysAdminParams.getAlfrescoContext());
|
||||
sysAdminParams.getAlfrescoProtocol(),
|
||||
sysAdminParams.getAlfrescoHost(),
|
||||
sysAdminParams.getAlfrescoPort(),
|
||||
sysAdminParams.getAlfrescoContext());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds up the Url to Share based on the settings in the
|
||||
* {@link SysAdminParams}.
|
||||
* @return Alfresco Url such as https://col.ab.or.ate/share/
|
||||
* or http://localhost:8081/share/
|
||||
* Builds up the Url to Share based on the settings in the
|
||||
* {@link SysAdminParams}.
|
||||
* @return Alfresco Url such as {@code https://col.ab.or.ate/share}
|
||||
* or {@code http://localhost:8081/share}
|
||||
*/
|
||||
public static String getShareUrl(SysAdminParams sysAdminParams)
|
||||
{
|
||||
return buildUrl(
|
||||
sysAdminParams.getShareProtocol(),
|
||||
sysAdminParams.getShareHost(),
|
||||
sysAdminParams.getSharePort(),
|
||||
sysAdminParams.getShareContext());
|
||||
sysAdminParams.getShareProtocol(),
|
||||
sysAdminParams.getShareHost(),
|
||||
sysAdminParams.getSharePort(),
|
||||
sysAdminParams.getShareContext());
|
||||
}
|
||||
|
||||
|
||||
@@ -80,8 +99,8 @@ public class UrlUtil
|
||||
/**
|
||||
* Builds URL to Api-Explorer based on the request only if the URL property is not provided
|
||||
* {@link SysAdminParams}.
|
||||
* @return Rest-Api Url such as https://col.ab.or.ate/api-explorer/
|
||||
* or http://localhost:8082/api-explorer/
|
||||
* @return Rest-Api Url such as {@code https://col.ab.or.ate/api-explorer}
|
||||
* or {@code http://localhost:8082/api-explorer}
|
||||
*/
|
||||
public static String getApiExplorerUrl(SysAdminParams sysAdminParams, String requestURL, String requestURI)
|
||||
{
|
||||
@@ -124,6 +143,12 @@ public class UrlUtil
|
||||
}
|
||||
|
||||
protected static String buildUrl(String protocol, String host, int port, String context)
|
||||
{
|
||||
String baseUrl = buildBaseUrl(protocol, host, port);
|
||||
return baseUrl + '/' + context;
|
||||
}
|
||||
|
||||
protected static String buildBaseUrl(String protocol, String host, int port)
|
||||
{
|
||||
StringBuilder url = new StringBuilder();
|
||||
url.append(protocol);
|
||||
@@ -142,8 +167,33 @@ public class UrlUtil
|
||||
url.append(':');
|
||||
url.append(port);
|
||||
}
|
||||
url.append('/');
|
||||
url.append(context);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the repo base url placeholder, namely {@literal ${repoBaseUrl}}, with value based on the settings in the
|
||||
* {@link SysAdminParams}.
|
||||
*
|
||||
* @param value the string value which contains the repoBase url placeholder
|
||||
* @param sysAdminParams the {@code SysAdminParams} object
|
||||
* @return if the given {@code value} contains repoBase url placeholder,
|
||||
* the placeholder is replaced with repoBase url; otherwise, the given {@code value} is simply returned
|
||||
*/
|
||||
public static String replaceRepoBaseUrlPlaceholder(String value, SysAdminParams sysAdminParams)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
return REPO_BASE_PATTERN.matcher(value).replaceAll(getAlfrescoBaseUrl(sysAdminParams));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static String replaceUrlPlaceholder(Pattern pattern, String value, String replacement)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
return pattern.matcher(value).replaceAll(replacement);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
# a NodeRef of the template
|
||||
# a class path of the template
|
||||
|
||||
# template assets url for share client
|
||||
repo.client-app.share.templateAssetsUrl=${shareUrl}/res/components/images/
|
||||
# template assets url for share client. i.e. The source url for the images/logo within the email
|
||||
repo.client-app.share.templateAssetsUrl=${shareUrl}/res/components/images
|
||||
# shared-link (quickShare) base url
|
||||
repo.client-app.share.sharedLinkBaseUrl=${shareUrl}/s
|
||||
# shared-link email template path
|
||||
@@ -20,6 +20,14 @@ repo.client-app.share.resetPasswordPageUrl=${shareUrl}/page/reset-password
|
||||
repo.client-app.share.confirmResetPasswordTemplatePath=
|
||||
|
||||
### Digital workspace template configurations
|
||||
repo.client-app.workspace.workspaceUrl=${repoBaseUrl}/workspace
|
||||
repo.client-app.workspace.inviteModeratedTemplatePath=
|
||||
repo.client-app.workspace.workspaceUrl=workspace
|
||||
repo.client-app.workspace.templateAssetsUrl=${alfrescoUrl}/images
|
||||
# template assets url for workspace client. i.e. The source url for the images/logo within the email
|
||||
repo.client-app.workspace.templateAssetsUrl=${repoBaseUrl}/alfresco/images/logo
|
||||
|
||||
# reset password request email template path
|
||||
repo.client-app.workspace.requestResetPasswordTemplatePath=alfresco/templates/reset-password-email-templates/forgot-password-email-template.ftl
|
||||
# reset password UI page url
|
||||
repo.client-app.workspace.resetPasswordPageUrl=${workspaceUrl}/reset-password
|
||||
# reset password confirmation email template path
|
||||
repo.client-app.workspace.confirmResetPasswordTemplatePath=
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
repository.name=Main Repository
|
||||
|
||||
# Schema number
|
||||
version.schema=18100
|
||||
version.schema=18000
|
||||
|
||||
# Directory configuration
|
||||
|
||||
@@ -752,16 +752,12 @@ encryption.ssl.truststore.keyMetaData.location=
|
||||
## HttpClient config for Transform Service
|
||||
#enable mtls in HttpClientFactory for Transform Service.
|
||||
httpclient.config.transform.mTLSEnabled=false
|
||||
httpclient.config.transform.maxTotalConnections=20
|
||||
httpclient.config.transform.maxHostConnections=20
|
||||
httpclient.config.transform.maxTotalConnections=40
|
||||
httpclient.config.transform.maxHostConnections=40
|
||||
httpclient.config.transform.socketTimeout=5000
|
||||
httpclient.config.transform.connectionRequestTimeout=5000
|
||||
httpclient.config.transform.connectionTimeout=5000
|
||||
|
||||
# Property is disabled by default for security reasons, never enable it on for production environments.
|
||||
# It will stop verification of hostnames placed in certificates returned with server responses to Repository requests towards transform services
|
||||
httpclient.config.transform.hostnameVerificationDisabled=false
|
||||
|
||||
# Re-encryptor properties
|
||||
encryption.reencryptor.chunkSize=100
|
||||
encryption.reencryptor.numThreads=2
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
td {
|
||||
font-family: 'Helvetica Neue', Arial, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: none;
|
||||
width: 100% ! important;
|
||||
height: 100% !important;
|
||||
color: #727174;
|
||||
font-weight: 400;
|
||||
font-size: 18px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #727174;
|
||||
font-weight: 600;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0c79bf;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.linkone {
|
||||
color: #0c79bf;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.appleLinks a {
|
||||
color: #0c79bf;
|
||||
}
|
||||
|
||||
.appleLinksWhite a {
|
||||
color: #0c79bf;
|
||||
}
|
||||
|
||||
.force-full-width {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.body-padding {
|
||||
padding: 0 75px
|
||||
}
|
||||
|
||||
.force-width-80 {
|
||||
width: 80% !important;
|
||||
}
|
||||
|
||||
p {
|
||||
Margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.button {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
font-family: sans-serif;
|
||||
font-weight: 400;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.button a {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 600px;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
}
|
||||
|
||||
#outlook a {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ReadMsgBody {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.backgroundTable {
|
||||
margin: 0 auto;
|
||||
padding: 0;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
table td {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.ExternalClass * {
|
||||
line-height: 115%;
|
||||
}
|
||||
|
||||
.ExternalClass {
|
||||
vertical-align: middle
|
||||
}
|
||||
|
||||
/*]]>*/
|
||||
</style>
|
||||
<style type="text/css" media="screen">
|
||||
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { {
|
||||
@-ms-viewport {
|
||||
width: 320px;
|
||||
}
|
||||
@viewport {
|
||||
width: 320px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style type="text/css" media="screen">
|
||||
@media screen {
|
||||
* {
|
||||
font-family: 'Helvetica Neue', 'Arial', 'sans-serif' !important;
|
||||
}
|
||||
|
||||
.w280 {
|
||||
width: 280px !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<style type="text/css" media="only screen and (max-width: 480px)">
|
||||
@media only screen and (max-width: 480px) {
|
||||
.full {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table[class*="w320"] {
|
||||
width: 320px !important;
|
||||
}
|
||||
|
||||
td[class*="w320"] {
|
||||
width: 280px !important;
|
||||
padding-left: 20px !important;
|
||||
padding-right: 20px !important;
|
||||
}
|
||||
|
||||
img[class*="w320"] {
|
||||
width: 250px !important;
|
||||
height: 67px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-spacing"] {
|
||||
padding-top: 10px !important;
|
||||
padding-bottom: 10px !important;
|
||||
}
|
||||
|
||||
*[class*="mobile-hide"] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
*[class*="mobile-br"] {
|
||||
font-size: 8px !important;
|
||||
}
|
||||
|
||||
*[class*="mobile-brh"] {
|
||||
font-size: 1px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-w20"] {
|
||||
width: 20px !important;
|
||||
}
|
||||
|
||||
img[class*="mobile-w20"] {
|
||||
width: 20px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-center"] {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
table[class*="w100p"] {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
td[class*="activate-now"] {
|
||||
padding-right: 0 !important;
|
||||
padding-top: 20px !important;
|
||||
}
|
||||
|
||||
td[class*="mobile-resize"] {
|
||||
font-size: 22px !important;
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body offset="0" class="body" style="padding:0; margin:0; display:block; background:#f3f4f4; -webkit-text-size-adjust:none; " bgcolor="#EEEEEE">
|
||||
<table align="center" cellpadding="0" cellspacing="0" width="100%" height="100%">
|
||||
<tr>
|
||||
<td align="center" valign="top" style="background-color:#f3f4f4; " width="100%">
|
||||
<table cellspacing="0" cellpadding="0" width="600" class="w320">
|
||||
<tr>
|
||||
<td align="center" valign="top">
|
||||
|
||||
<!--Snippet Block-->
|
||||
<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%">
|
||||
<tr>
|
||||
<td>
|
||||
<table border="0" cellspacing="0" cellpadding="10" width="100%" align="center">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">
|
||||
<table align="center" width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td align="right">
|
||||
<div style="display:none;font-size:1px;color:#333333;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;">
|
||||
-
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Header Block-->
|
||||
<table bgcolor="#FFFFFF" border="0" cellspacing="0" cellpadding="0" align="center" width="100%"
|
||||
style="border-left:solid 1px #dedee4; border-right:solid 1px #dedee4; border-bottom:solid 1px #dedee4; border-top:solid 1px #dedee4; width:100%!important; min-width:100%;">
|
||||
<tr style="width:100%;">
|
||||
<td>
|
||||
<table border="0" cellspacing="0" cellpadding="10" align="center" width="100%">
|
||||
<tr>
|
||||
<td align="left" valign="middle"><a style="color: #ffffff; text-decoration: none;" href=
|
||||
"https://www.alfresco.com/" target="_blank"
|
||||
><span style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 24px; color: #727174;"><img
|
||||
style="border:none; display:block; border-collapse:collapse; outline:none; text-decoration:none;"
|
||||
src="${template_assets_url}/hyland_logo.png" border="0"
|
||||
alt="Alfresco" width="122" height="38"></span></a></td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
<td align="right" bgcolor="#FFFFFF">
|
||||
<table border="0" cellspacing="0" cellpadding="10" align="center" width="100%">
|
||||
<tr>
|
||||
<td align="right" valign="middle"><span
|
||||
style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 16px; font-weight:200; color: #727174;">Digital Workspace</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="10">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Body Block 1-->
|
||||
<!--Banner Block-->
|
||||
<table cellspacing="0" cellpadding="0" width="100%" style="border-left:solid 1px #dedee4; border-right:solid 1px #dedee4; ">
|
||||
<tr>
|
||||
<td style="border-collapse:collapse; ">
|
||||
<table cellspacing="0" cellpadding="0" width="100%" style="background-color:#0c79bf; border:none; ">
|
||||
<tr>
|
||||
<td style="border-collapse:collapse; ">
|
||||
<div class="mktEditable" id="Banner Image 1"><span
|
||||
style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 24px; color: #ffffff;"><img
|
||||
src="${template_assets_url}/adw_logo.png" alt="Alfresco Products" style="width:100%; border:none;
|
||||
display:block; border-collapse:collapse; outline:none; text-decoration:none;"></span></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--Copy-->
|
||||
<table cellspacing="0" cellpadding="0" align="center" bgcolor="#FFFFFF"
|
||||
style="border-left:solid 1px #dedee4; border-right:solid 1px #dedee4; border-bottom:solid 1px #dedee4; " width="100%">
|
||||
<tr align="center">
|
||||
<td style="background-color:#ffffff; " align="center">
|
||||
<table class="force-width-80" cellspacing="0" cellpadding="12" align="center" bgcolor="#FFFFFF" width="80%">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="left">
|
||||
<!--Headline Text-->
|
||||
<div class="mktEditable" id="Headline Text 1" align="left" style="vertical-align:middle; "><span
|
||||
style="color: #727174; margin: 0px; font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 22px; font-weight: 600; text-align: left; text-decoration: none; vertical-align:
|
||||
middle;"><p>${message("templates.reset-password-email.ftl.title")}</p></span></div>
|
||||
<div class="mktEditable" id="Body Text 1" align="left">
|
||||
<span style="color:#727174; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:18px;font-weight:400; text-align:left; text-decoration:none; -webkit-text-size-adjust:none;">
|
||||
<p>${message("templates.reset-password-email.ftl.detail")}</p>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="5">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Button-->
|
||||
<table style="margin:0 auto; " cellspacing="0" cellpadding="0" width="100%">
|
||||
<tr>
|
||||
<td style="text-align:center; margin:0 auto; ">
|
||||
<div><!--[if mso]>
|
||||
<v:rect xmlns:v="urn:schemas-microsoft-com:vml"
|
||||
xmlns:w="urn:schemas-microsoft-com:office:word"
|
||||
style="height:45px;v-text-anchor:middle;width:220px;" stroke="f"
|
||||
fillcolor="#47AA2">
|
||||
<w:anchorlock/>
|
||||
<center>
|
||||
<![endif]-->
|
||||
<div class="mktEditable" id="Button Text"><a href="${reset_password_url}" style="background-color:#47aa42; color:#ffffff; display:inline-block; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:18px; font-weight:400; line-height:45px; text-align:center; text-decoration:none; width:220px;
|
||||
-webkit-text-size-adjust:none;">${message("templates.reset-password-email.ftl.reset_password_button")}</a></div>
|
||||
<span style="color:#727174; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:12px;font-weight:400; text-align:left; text-decoration:none; -webkit-text-size-adjust:none;">
|
||||
<p>${message("templates.reset-password-email.ftl.ignore_message")}</p>
|
||||
<span style="color:#727174; font-family:Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:12px;font-weight:400; text-align:left; text-decoration:none; -webkit-text-size-adjust:none;">
|
||||
<hr>
|
||||
<p>${message("templates.reset-password-email.ftl.having_trouble_clicking_button")}</p>
|
||||
<p><a href="${reset_password_url}">${reset_password_url}</a></p>
|
||||
</span>
|
||||
<!--[if mso]>
|
||||
</center>
|
||||
</v:rect>
|
||||
<![endif]--></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="5">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="10">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Footer Block-->
|
||||
<table border="0" cellspacing="0" cellpadding="0" align="center" width="100%">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a style="color: #0c79bf; text-decoration: underline;" href="http://www.alfresco.com/company/contact"
|
||||
target="_blank"><span
|
||||
style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #0c79bf;">${message("templates.generic-email.ftl.contact_us")}</span></a>
|
||||
<span style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial,
|
||||
sans-serif; font-size: 10px; color: #b3b3b8;">© ${date?string["yyyy"]} Alfresco Software, Inc.
|
||||
${message("templates.generic-email.ftl.copy_right")}</span><br>
|
||||
<span style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #b3b3b8;">Bridge Ave, The Place Maidenhead SL6 1AF United Kingdom</span><br>
|
||||
<span style="font-family: Gotham, 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10px; color: #b3b3b8;">1825 S Grant St, Suite 900 San Mateo, CA 94402 USA</span><br>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!--Break-->
|
||||
<table width="100%">
|
||||
<tr>
|
||||
<td height="10">
|
||||
<div class="mobile-br"> </div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--Litmus Tracking-->
|
||||
<table style="display: none;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 0px; display: none; overflow: hidden; max-height: 0px;">{{my.Litmus_Code}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@@ -250,7 +250,8 @@ import org.junit.runners.Suite;
|
||||
org.alfresco.repo.event2.RepoEvent2UnitSuite.class,
|
||||
|
||||
org.alfresco.util.schemacomp.SchemaDifferenceHelperUnitTest.class,
|
||||
org.alfresco.repo.tagging.TaggingServiceImplUnitTest.class
|
||||
org.alfresco.repo.tagging.TaggingServiceImplUnitTest.class,
|
||||
org.alfresco.repo.client.config.ClientAppConfigUnitTest.class
|
||||
})
|
||||
public class AllUnitTestsSuite
|
||||
{
|
||||
|
||||
@@ -31,16 +31,12 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import org.alfresco.repo.client.config.ClientAppConfig.ClientApp;
|
||||
import org.alfresco.service.cmr.repository.TemporalSourceOptions;
|
||||
import org.alfresco.util.ApplicationContextHelper;
|
||||
import org.alfresco.util.testing.category.LuceneTests;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -53,15 +49,15 @@ import java.util.Map;
|
||||
@Category(LuceneTests.class)
|
||||
public class ClientAppConfigTest
|
||||
{
|
||||
private ApplicationContext context;
|
||||
private ClientAppConfig clientAppConfig;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
{
|
||||
ApplicationContextHelper.closeApplicationContext();
|
||||
context = ApplicationContextHelper.getApplicationContext(new String[] { ApplicationContextHelper.CONFIG_LOCATIONS[0],
|
||||
"classpath:org/alfresco/repo/client/config/test-repo-clients-apps-context.xml" });
|
||||
ApplicationContext context = ApplicationContextHelper.getApplicationContext(
|
||||
new String[] { ApplicationContextHelper.CONFIG_LOCATIONS[0],
|
||||
"classpath:org/alfresco/repo/client/config/test-repo-clients-apps-context.xml" });
|
||||
|
||||
clientAppConfig = context.getBean("clientAppConfigTest", ClientAppConfig.class);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* 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.repo.client.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.alfresco.repo.admin.SysAdminParams;
|
||||
import org.alfresco.repo.client.config.ClientAppConfig.ClientApp;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
/**
|
||||
* @author Jamal Kaabi-Mofrad
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ClientAppConfigUnitTest
|
||||
{
|
||||
private ClientAppConfig clientAppConfig;
|
||||
@Mock
|
||||
private SysAdminParams sysAdminParams;
|
||||
|
||||
private AtomicBoolean initialised;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception
|
||||
|
||||
{ // This in not initialised yet. i.e. the properties are not processed yet.
|
||||
// The processing will start when you call the 'onBootstrap()' method
|
||||
clientAppConfig = buildClientAppConfig();
|
||||
|
||||
initialised = new AtomicBoolean(false);
|
||||
|
||||
when(sysAdminParams.getAlfrescoProtocol()).thenReturn("http");
|
||||
when(sysAdminParams.getAlfrescoHost()).thenReturn("localhost");
|
||||
when(sysAdminParams.getAlfrescoPort()).thenReturn(8080);
|
||||
|
||||
when(sysAdminParams.getShareProtocol()).thenReturn("http");
|
||||
when(sysAdminParams.getShareHost()).thenReturn("localhost");
|
||||
when(sysAdminParams.getSharePort()).thenReturn(8081);
|
||||
when(sysAdminParams.getShareContext()).thenReturn("share");
|
||||
}
|
||||
|
||||
private ClientAppConfig buildClientAppConfig()
|
||||
{
|
||||
Properties defaultProps = getWorkspaceAppProperties();
|
||||
defaultProps.putAll(getCoolAppProperties());
|
||||
defaultProps.putAll(getShareProperties());
|
||||
Properties globalProps = new Properties();
|
||||
|
||||
ClientAppConfig config = new ClientAppConfig();
|
||||
config.setDefaultProperties(defaultProps);
|
||||
config.setGlobalProperties(globalProps);
|
||||
return config;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWorkspaceClient()
|
||||
{
|
||||
ClientApp client = getClientApp("workspace");
|
||||
assertEquals("workspace", client.getName());
|
||||
assertEquals("${workspaceUrl}/images", client.getTemplateAssetsUrl());
|
||||
assertEquals("${repoBaseUrl}/workspace", client.getClientUrl());
|
||||
assertEquals("workspaceUrl", client.getClientUrlPropKey());
|
||||
assertEquals("\\$\\{workspaceUrl}", client.getClientUrlPlaceholderPattern()
|
||||
.pattern());
|
||||
|
||||
Map<String, String> properties = client.getProperties();
|
||||
assertNotNull(properties);
|
||||
assertNull("Not Set", properties.get("inviteModeratedTemplatePath"));
|
||||
assertEquals("alfresco/templates/test-email-templates/test-email-template.ftl",
|
||||
properties.get("requestResetPasswordTemplatePath"));
|
||||
assertEquals("${workspaceUrl}/reset-password", properties.get("resetPasswordPageUrl"));
|
||||
assertEquals("some/path", properties.get("confirmResetPasswordTemplatePath"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCoolAppClient()
|
||||
{
|
||||
ClientApp client = getClientApp("coolApp");
|
||||
assertEquals("coolApp", client.getName());
|
||||
assertEquals("${coolAppUrl}/images", client.getTemplateAssetsUrl());
|
||||
assertEquals("http://localhost:8090/cool-app", client.getClientUrl());
|
||||
assertEquals("coolAppUrl", client.getClientUrlPropKey());
|
||||
assertEquals("\\$\\{coolAppUrl}", client.getClientUrlPlaceholderPattern()
|
||||
.pattern());
|
||||
|
||||
Map<String, String> properties = client.getProperties();
|
||||
assertNotNull(properties);
|
||||
assertEquals("${coolAppUrl}/page-one/page-two", properties.get("testPropUrl"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveWorkspacePlaceholders()
|
||||
{
|
||||
ClientApp client = getClientApp("workspace");
|
||||
// Raw properties
|
||||
assertEquals("${repoBaseUrl}/workspace", client.getClientUrl());
|
||||
assertEquals("workspaceUrl", client.getClientUrlPropKey());
|
||||
assertEquals("\\$\\{workspaceUrl}", client.getClientUrlPlaceholderPattern()
|
||||
.pattern());
|
||||
assertEquals("${workspaceUrl}/images", client.getTemplateAssetsUrl());
|
||||
assertEquals("${workspaceUrl}/reset-password", client.getProperty("resetPasswordPageUrl"));
|
||||
|
||||
// Resolved properties
|
||||
// String clientUrl = UrlUtil.replaceRepoBaseUrlPlaceholder(client.getClientUrl(), sysAdminParams);
|
||||
assertEquals("http://localhost:8080/workspace", client.getResolvedClientUrl(sysAdminParams));
|
||||
assertEquals("http://localhost:8080/workspace/images", client.getResolvedTemplateAssetsUrl(sysAdminParams));
|
||||
assertEquals("http://localhost:8080/workspace/reset-password",
|
||||
client.getResolvedProperty("resetPasswordPageUrl", sysAdminParams));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveCoolAppPlaceholders()
|
||||
{
|
||||
ClientApp client = getClientApp("coolApp");
|
||||
// Resolved properties
|
||||
assertEquals("http://localhost:8090/cool-app", client.getResolvedClientUrl(sysAdminParams));
|
||||
assertEquals("http://localhost:8090/cool-app/images", client.getResolvedTemplateAssetsUrl(sysAdminParams));
|
||||
assertEquals("http://localhost:8090/cool-app/page-one/page-two",
|
||||
client.getResolvedProperty("testPropUrl", sysAdminParams));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveSharePlaceholders()
|
||||
{
|
||||
ClientApp client = getClientApp("share");
|
||||
// Resolved properties
|
||||
assertEquals("http://localhost:8081/share", client.getResolvedClientUrl(sysAdminParams));
|
||||
assertEquals("http://localhost:8081/share/res/components/images",
|
||||
client.getResolvedTemplateAssetsUrl(sysAdminParams));
|
||||
assertEquals("http://localhost:8081/share/page/reset-password",
|
||||
client.getResolvedProperty("resetPasswordPageUrl", sysAdminParams));
|
||||
assertEquals("http://localhost:8081/share/s", client.getResolvedProperty("sharedLinkBaseUrl", sysAdminParams));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientsPropertiesOverride()
|
||||
{
|
||||
Properties globalProps = new Properties();
|
||||
globalProps.put("repo.client-app.workspace.workspaceUrl", "https://develop.envalfresco.com/#");
|
||||
globalProps.put("repo.client-app.share.shareUrl", "https://develop.envalfresco.com/share");
|
||||
globalProps.put("repo.client-app.coolApp.coolAppUrl", "https://develop.envalfresco.com/eval/cool-app");
|
||||
|
||||
clientAppConfig.setGlobalProperties(globalProps);
|
||||
|
||||
/*
|
||||
* Workspace client URL Override
|
||||
*/
|
||||
ClientApp workspaceClient = getClientApp("workspace");
|
||||
// Resolved properties
|
||||
assertEquals("https://develop.envalfresco.com/#", workspaceClient.getResolvedClientUrl(sysAdminParams));
|
||||
assertEquals("https://develop.envalfresco.com/#/images",
|
||||
workspaceClient.getResolvedTemplateAssetsUrl(sysAdminParams));
|
||||
assertEquals("https://develop.envalfresco.com/#/reset-password",
|
||||
workspaceClient.getResolvedProperty("resetPasswordPageUrl", sysAdminParams));
|
||||
|
||||
/*
|
||||
* Share client URL Override
|
||||
*/
|
||||
ClientApp shareClient = getClientApp("share");
|
||||
// Resolved properties
|
||||
assertEquals("https://develop.envalfresco.com/share", shareClient.getResolvedClientUrl(sysAdminParams));
|
||||
assertEquals("https://develop.envalfresco.com/share/res/components/images",
|
||||
shareClient.getResolvedTemplateAssetsUrl(sysAdminParams));
|
||||
assertEquals("https://develop.envalfresco.com/share/page/reset-password",
|
||||
shareClient.getResolvedProperty("resetPasswordPageUrl", sysAdminParams));
|
||||
assertEquals("https://develop.envalfresco.com/share/s",
|
||||
shareClient.getResolvedProperty("sharedLinkBaseUrl", sysAdminParams));
|
||||
|
||||
/*
|
||||
* coolApp client URL Override
|
||||
*/
|
||||
ClientApp coolAppClient = getClientApp("coolApp");
|
||||
// Resolved properties
|
||||
assertEquals("https://develop.envalfresco.com/eval/cool-app",
|
||||
coolAppClient.getResolvedClientUrl(sysAdminParams));
|
||||
assertEquals("https://develop.envalfresco.com/eval/cool-app/images",
|
||||
coolAppClient.getResolvedTemplateAssetsUrl(sysAdminParams));
|
||||
assertEquals("https://develop.envalfresco.com/eval/cool-app/page-one/page-two",
|
||||
coolAppClient.getResolvedProperty("testPropUrl", sysAdminParams));
|
||||
}
|
||||
|
||||
private Properties getWorkspaceAppProperties()
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.put("repo.client-app.workspace.inviteModeratedTemplatePath", "");
|
||||
props.put("repo.client-app.workspace.workspaceUrl", "${repoBaseUrl}/workspace");
|
||||
props.put("repo.client-app.workspace.templateAssetsUrl", "${workspaceUrl}/images");
|
||||
props.put("repo.client-app.workspace.requestResetPasswordTemplatePath",
|
||||
"alfresco/templates/test-email-templates/test-email-template.ftl");
|
||||
props.put("repo.client-app.workspace.resetPasswordPageUrl", "${workspaceUrl}/reset-password");
|
||||
props.put("repo.client-app.workspace.confirmResetPasswordTemplatePath", "some/path");
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
private Properties getShareProperties()
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.put("repo.client-app.share.templateAssetsUrl", "${shareUrl}/res/components/images");
|
||||
props.put("repo.client-app.share.resetPasswordPageUrl", "${shareUrl}/page/reset-password");
|
||||
props.put("repo.client-app.share.sharedLinkBaseUrl", "${shareUrl}/s");
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
private Properties getCoolAppProperties()
|
||||
{
|
||||
Properties props = new Properties();
|
||||
props.put("repo.client-app.coolApp.coolAppUrl", "http://localhost:8090/cool-app");
|
||||
props.put("repo.client-app.coolApp.templateAssetsUrl", "${coolAppUrl}/images");
|
||||
props.put("repo.client-app.coolApp.testPropUrl", "${coolAppUrl}/page-one/page-two");
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
private ClientApp getClientApp(String clientName)
|
||||
{
|
||||
if (!initialised.get())
|
||||
{
|
||||
clientAppConfig.onBootstrap(null);
|
||||
initialised.set(true);
|
||||
}
|
||||
Map<String, ClientApp> clients = clientAppConfig.getClients();
|
||||
assertFalse(clients.isEmpty());
|
||||
assertTrue(clientName + " client is expected.", clientAppConfig.exists(clientName));
|
||||
ClientApp client = clients.get(clientName);
|
||||
assertNotNull(clientName + " client can't be null.", client);
|
||||
return client;
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,6 @@ import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
@@ -420,65 +419,6 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
assertTrue("New rendition content hash code was not generated", isValidRenditionContentHashCode(contentHashCode3));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testModifierAfterMultipleRenditionRequests() throws InterruptedException
|
||||
{
|
||||
String user1 = createRandomUser();
|
||||
String user2 = createRandomUser();
|
||||
List<NodeRef> nodes = new ArrayList<NodeRef>();
|
||||
|
||||
final int TOTAL_NODES = 10;
|
||||
|
||||
// Create nodes
|
||||
for (int i = 0; i < TOTAL_NODES; i++)
|
||||
{
|
||||
NodeRef n = createSource(user1, "quick.jpg");
|
||||
render(user1, n, DOC_LIB);
|
||||
nodes.add(n);
|
||||
}
|
||||
|
||||
// Ask rendition multiple times with 'user2'
|
||||
for (int j = 0; j < 10; j++)
|
||||
{
|
||||
for (int i = 0; i < TOTAL_NODES; i++)
|
||||
{
|
||||
render(user2, nodes.get(i), DOC_LIB);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < TOTAL_NODES; i++)
|
||||
{
|
||||
waitForRendition(user1, nodes.get(i), DOC_LIB, true);
|
||||
}
|
||||
|
||||
// Check the modifier is still user1
|
||||
assertEquals(TOTAL_NODES, countModifier(nodes, user1));
|
||||
}
|
||||
|
||||
private int countModifier(List<NodeRef> nodes, String user)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < nodes.size(); i++)
|
||||
{
|
||||
count += compareModifier(nodes.get(i), user);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private int compareModifier(NodeRef nodeRef, String user)
|
||||
{
|
||||
int res = 0;
|
||||
if (nodeRef != null && user != null)
|
||||
{
|
||||
String modifier = nodeService.getProperty(nodeRef, ContentModel.PROP_MODIFIER).toString();
|
||||
if (user.equals(modifier))
|
||||
{
|
||||
res = 1;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated can be removed when we remove the original RenditionService
|
||||
*/
|
||||
@@ -682,4 +622,4 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
|
||||
renditionService2.setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,9 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.repo.admin.SysAdminParams;
|
||||
import org.alfresco.repo.client.config.ClientAppConfig;
|
||||
import org.alfresco.repo.client.config.ClientAppConfig.ClientApp;
|
||||
import org.alfresco.repo.client.config.ClientAppNotFoundException;
|
||||
import org.alfresco.repo.security.authentication.ResetPasswordServiceImpl.InvalidResetPasswordWorkflowException;
|
||||
import org.alfresco.repo.security.authentication.ResetPasswordServiceImpl.ResetPasswordDetails;
|
||||
@@ -47,6 +50,7 @@ import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.GUID;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.alfresco.util.TestHelper;
|
||||
import org.alfresco.util.UrlUtil;
|
||||
import org.alfresco.util.email.EmailUtil;
|
||||
import org.alfresco.util.test.junitrules.ApplicationContextInit;
|
||||
import org.alfresco.util.test.junitrules.RunAsFullyAuthenticatedRule;
|
||||
@@ -88,9 +92,12 @@ public class ResetPasswordServiceImplTest
|
||||
private static PersonService personService;
|
||||
private static Properties globalProperties;
|
||||
private static WorkflowService workflowService;
|
||||
private static ClientAppConfig clientAppConfig;
|
||||
private static SysAdminParams sysAdminParams;
|
||||
|
||||
private static TestPerson testPerson;
|
||||
private static EmailUtil emailUtil;
|
||||
private static TestPerson testPerson1;
|
||||
private static TestPerson testPerson2;
|
||||
private static EmailUtil emailUtil;
|
||||
|
||||
@BeforeClass
|
||||
public static void initStaticData() throws Exception
|
||||
@@ -103,36 +110,57 @@ public class ResetPasswordServiceImplTest
|
||||
personService = APP_CONTEXT_INIT.getApplicationContext().getBean("personService", PersonService.class);
|
||||
globalProperties = APP_CONTEXT_INIT.getApplicationContext().getBean("global-properties", Properties.class);
|
||||
workflowService = APP_CONTEXT_INIT.getApplicationContext().getBean("WorkflowService", WorkflowService.class);
|
||||
clientAppConfig = APP_CONTEXT_INIT.getApplicationContext().getBean("clientAppConfig", ClientAppConfig.class);
|
||||
sysAdminParams = APP_CONTEXT_INIT.getApplicationContext().getBean("sysAdminParams", SysAdminParams.class);
|
||||
emailUtil = new EmailUtil(APP_CONTEXT_INIT.getApplicationContext());
|
||||
emailUtil.reset();
|
||||
|
||||
String userName = "jane.doe" + System.currentTimeMillis();
|
||||
testPerson = new TestPerson()
|
||||
.setUserName(userName)
|
||||
String userName1 = "jane.doe" + System.currentTimeMillis();
|
||||
testPerson1 = new TestPerson()
|
||||
.setUserName(userName1)
|
||||
.setFirstName("Jane")
|
||||
.setLastName("doe")
|
||||
.setLastName("Doe")
|
||||
.setPassword("password")
|
||||
.setEmail(userName + "@example.com");
|
||||
.setEmail(userName1 + "@example.com");
|
||||
|
||||
String userName2 = "sara.blogs" + System.currentTimeMillis();
|
||||
testPerson2 = new TestPerson()
|
||||
.setUserName(userName2)
|
||||
.setFirstName("Sara")
|
||||
.setLastName("Blogs")
|
||||
.setPassword("password")
|
||||
.setEmail(userName2 + "@example.com");
|
||||
|
||||
AuthenticationUtil.setRunAsUserSystem();
|
||||
transactionHelper.doInTransaction((RetryingTransactionCallback<Void>) () ->
|
||||
{
|
||||
createUser(testPerson);
|
||||
createUser(testPerson1);
|
||||
createUser(testPerson2);
|
||||
return null;
|
||||
});
|
||||
|
||||
// Restore authentication to pre-test state.
|
||||
try
|
||||
{
|
||||
AuthenticationUtil.popAuthentication();
|
||||
}
|
||||
catch(EmptyStackException e)
|
||||
{
|
||||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanUp()
|
||||
{
|
||||
resetPasswordService.setSendEmailAsynchronously(Boolean.valueOf(
|
||||
resetPasswordService.setSendEmailAsynchronously(Boolean.parseBoolean(
|
||||
globalProperties.getProperty("system.reset-password.sendEmailAsynchronously")));
|
||||
resetPasswordService.setDefaultEmailSender((String) globalProperties.get("system.email.sender.default"));
|
||||
|
||||
AuthenticationUtil.setRunAsUserSystem();
|
||||
transactionHelper.doInTransaction(() ->
|
||||
{
|
||||
personService.deletePerson(testPerson.userName);
|
||||
personService.deletePerson(testPerson1.userName);
|
||||
personService.deletePerson(testPerson2.userName);
|
||||
return null;
|
||||
});
|
||||
|
||||
@@ -157,21 +185,21 @@ public class ResetPasswordServiceImplTest
|
||||
public void testResetPassword() throws Exception
|
||||
{
|
||||
// Try the credential before change of password
|
||||
authenticateUser(testPerson.userName, testPerson.password);
|
||||
authenticateUser(testPerson1.userName, testPerson1.password);
|
||||
|
||||
// Make sure to run as system
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
AuthenticationUtil.setRunAsUserSystem();
|
||||
|
||||
// Request password reset
|
||||
resetPasswordService.requestReset(testPerson.userName, "share");
|
||||
resetPasswordService.requestReset(testPerson1.userName, "share");
|
||||
assertEquals("A reset password email should have been sent.", 1, emailUtil.getSentCount());
|
||||
// Check the email
|
||||
MimeMessage msg = emailUtil.getLastEmail();
|
||||
assertNotNull("There should be an email.", msg);
|
||||
assertEquals("Should've been only one email recipient.", 1, msg.getAllRecipients().length);
|
||||
// Check the recipient is the person who requested the reset password
|
||||
assertEquals(testPerson.email, msg.getAllRecipients()[0].toString());
|
||||
assertEquals(testPerson1.email, msg.getAllRecipients()[0].toString());
|
||||
//Check the sender is what we set as default
|
||||
assertEquals(DEFAULT_SENDER, msg.getFrom()[0].toString());
|
||||
// There should be a subject
|
||||
@@ -192,7 +220,7 @@ public class ResetPasswordServiceImplTest
|
||||
emailUtil.reset();
|
||||
// Now that we have got the email, try to reset the password
|
||||
ResetPasswordDetails passwordDetails = new ResetPasswordDetails()
|
||||
.setUserId(testPerson.userName)
|
||||
.setUserId(testPerson1.userName)
|
||||
.setPassword("newPassword")
|
||||
.setWorkflowId(pair.getFirst())
|
||||
.setWorkflowKey(pair.getSecond());
|
||||
@@ -204,7 +232,7 @@ public class ResetPasswordServiceImplTest
|
||||
assertNotNull("There should be an email.", msg);
|
||||
assertEquals("Should've been only one email recipient.", 1, msg.getAllRecipients().length);
|
||||
// Check the recipient is the person who requested the reset password
|
||||
assertEquals(testPerson.email, msg.getAllRecipients()[0].toString());
|
||||
assertEquals(testPerson1.email, msg.getAllRecipients()[0].toString());
|
||||
// Check the sender is what we set as default
|
||||
assertEquals(DEFAULT_SENDER, msg.getFrom()[0].toString());
|
||||
// There should be a subject
|
||||
@@ -215,12 +243,12 @@ public class ResetPasswordServiceImplTest
|
||||
assertEquals(msg.getSubject(), I18NUtil.getMessage(emailSubjectKey));
|
||||
|
||||
// Try the old credential
|
||||
TestHelper.assertThrows(() -> authenticateUser(testPerson.userName, testPerson.password),
|
||||
TestHelper.assertThrows(() -> authenticateUser(testPerson1.userName, testPerson1.password),
|
||||
AuthenticationException.class,
|
||||
"As the user changed her password, the authentication should have failed.");
|
||||
|
||||
// Try the new credential
|
||||
authenticateUser(testPerson.userName, "newPassword");
|
||||
authenticateUser(testPerson1.userName, "newPassword");
|
||||
|
||||
// Make sure to run as system
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
@@ -237,12 +265,12 @@ public class ResetPasswordServiceImplTest
|
||||
public void testRequestResetPasswordInvalid() throws Exception
|
||||
{
|
||||
// Request password reset
|
||||
TestHelper.assertThrows(() -> resetPasswordService.requestReset(testPerson.userName, null),
|
||||
TestHelper.assertThrows(() -> resetPasswordService.requestReset(testPerson1.userName, null),
|
||||
IllegalArgumentException.class,
|
||||
"Client name is mandatory.");
|
||||
|
||||
// Request password reset
|
||||
TestHelper.assertThrows(() -> resetPasswordService.requestReset(testPerson.userName, "TestClient" + System.currentTimeMillis()),
|
||||
TestHelper.assertThrows(() -> resetPasswordService.requestReset(testPerson1.userName, "TestClient" + System.currentTimeMillis()),
|
||||
ClientAppNotFoundException.class,
|
||||
"Client is not found.");
|
||||
assertEquals("No email should have been sent.", 0, emailUtil.getSentCount());
|
||||
@@ -260,23 +288,23 @@ public class ResetPasswordServiceImplTest
|
||||
assertEquals("No email should have been sent.", 0, emailUtil.getSentCount());
|
||||
|
||||
// Disable the user
|
||||
enableUser(testPerson.userName, false);
|
||||
enableUser(testPerson1.userName, false);
|
||||
|
||||
// Request password reset
|
||||
TestHelper.assertThrows(() -> resetPasswordService.requestReset(testPerson.userName, "share"),
|
||||
TestHelper.assertThrows(() -> resetPasswordService.requestReset(testPerson1.userName, "share"),
|
||||
ResetPasswordWorkflowInvalidUserException.class,
|
||||
"user is disabled.");
|
||||
assertEquals("No email should have been sent.", 0, emailUtil.getSentCount());
|
||||
|
||||
// Enable the user
|
||||
enableUser(testPerson.userName, true);
|
||||
enableUser(testPerson1.userName, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResetPasswordInvalid() throws Exception
|
||||
{
|
||||
// Request password reset
|
||||
resetPasswordService.requestReset(testPerson.userName, "share");
|
||||
resetPasswordService.requestReset(testPerson1.userName, "share");
|
||||
assertEquals("A reset password email should have been sent.", 1, emailUtil.getSentCount());
|
||||
// Check the email
|
||||
MimeMessage msg = emailUtil.getLastEmail();
|
||||
@@ -307,7 +335,7 @@ public class ResetPasswordServiceImplTest
|
||||
IllegalArgumentException.class,
|
||||
"User id is mandatory.");
|
||||
|
||||
passwordDetails.setUserId(testPerson.userName)
|
||||
passwordDetails.setUserId(testPerson1.userName)
|
||||
.setPassword(null); // Password is not provided
|
||||
TestHelper.assertThrows(() -> resetPasswordService.initiateResetPassword(passwordDetails),
|
||||
IllegalArgumentException.class,
|
||||
@@ -363,7 +391,7 @@ public class ResetPasswordServiceImplTest
|
||||
// Set the duration for 1 second
|
||||
resetPasswordService.setTimerEnd("PT1S");
|
||||
// Request password reset
|
||||
resetPasswordService.requestReset(testPerson.userName, "share");
|
||||
resetPasswordService.requestReset(testPerson1.userName, "share");
|
||||
assertEquals("A reset password email should have been sent.", 1, emailUtil.getSentCount());
|
||||
|
||||
// Check the reset password url.
|
||||
@@ -377,7 +405,7 @@ public class ResetPasswordServiceImplTest
|
||||
emailUtil.reset();
|
||||
// Now that we have got the email, try to reset the password
|
||||
ResetPasswordDetails passwordDetails = new ResetPasswordDetails()
|
||||
.setUserId(testPerson.userName)
|
||||
.setUserId(testPerson1.userName)
|
||||
.setPassword("newPassword")
|
||||
.setWorkflowId(pair.getFirst())
|
||||
.setWorkflowKey(pair.getSecond());
|
||||
@@ -396,6 +424,110 @@ public class ResetPasswordServiceImplTest
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResetPasswordForClientWorkspace() throws Exception
|
||||
{
|
||||
// Try the credential before change of password
|
||||
authenticateUser(testPerson2.userName, testPerson2.password);
|
||||
|
||||
// Make sure to run as system
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
AuthenticationUtil.setRunAsUserSystem();
|
||||
|
||||
// Request password reset
|
||||
resetPasswordService.requestReset(testPerson2.userName, "workspace");
|
||||
assertEquals("A reset password email should have been sent.", 1, emailUtil.getSentCount());
|
||||
// Check the email
|
||||
MimeMessage msg = emailUtil.getLastEmail();
|
||||
assertNotNull("There should be an email.", msg);
|
||||
assertEquals("Should've been only one email recipient.", 1, msg.getAllRecipients().length);
|
||||
// Check the recipient is the person who requested the reset password
|
||||
assertEquals(testPerson2.email, msg.getAllRecipients()[0].toString());
|
||||
//Check the sender is what we set as default
|
||||
assertEquals(DEFAULT_SENDER, msg.getFrom()[0].toString());
|
||||
// There should be a subject
|
||||
assertNotNull("There should be a subject.", msg.getSubject());
|
||||
// Check the default email subject - (check that we are sending the right email)
|
||||
String emailSubjectKey = getDeclaredField(SendResetPasswordEmailDelegate.class, "EMAIL_SUBJECT_KEY");
|
||||
assertNotNull(emailSubjectKey);
|
||||
assertEquals(msg.getSubject(), I18NUtil.getMessage(emailSubjectKey));
|
||||
|
||||
// Check the reset password url.
|
||||
String resetPasswordUrl = (String) emailUtil.getLastEmailTemplateModelValue("reset_password_url");
|
||||
assertNotNull("Wrong email is sent.", resetPasswordUrl);
|
||||
// Get the workflow id and key
|
||||
Pair<String, String> pair = getWorkflowIdAndKeyFromUrl(resetPasswordUrl);
|
||||
assertNotNull("Workflow Id can't be null.", pair.getFirst());
|
||||
assertNotNull("Workflow Key can't be null.", pair.getSecond());
|
||||
|
||||
emailUtil.reset();
|
||||
// Now that we have got the email, try to reset the password
|
||||
ResetPasswordDetails passwordDetails = new ResetPasswordDetails()
|
||||
.setUserId(testPerson2.userName)
|
||||
.setPassword("strongPassword")
|
||||
.setWorkflowId(pair.getFirst())
|
||||
.setWorkflowKey(pair.getSecond());
|
||||
|
||||
resetPasswordService.initiateResetPassword(passwordDetails);
|
||||
assertEquals("A reset password confirmation email should have been sent.", 1, emailUtil.getSentCount());
|
||||
// Check the email
|
||||
msg = emailUtil.getLastEmail();
|
||||
assertNotNull("There should be an email.", msg);
|
||||
assertEquals("Should've been only one email recipient.", 1, msg.getAllRecipients().length);
|
||||
// Check the recipient is the person who requested the reset password
|
||||
assertEquals(testPerson2.email, msg.getAllRecipients()[0].toString());
|
||||
// Check the sender is what we set as default
|
||||
assertEquals(DEFAULT_SENDER, msg.getFrom()[0].toString());
|
||||
// There should be a subject
|
||||
assertNotNull("There should be a subject.", msg.getSubject());
|
||||
// Check the default email subject - (check that we are sending the right email)
|
||||
emailSubjectKey = getDeclaredField(SendResetPasswordConfirmationEmailDelegate.class, "EMAIL_SUBJECT_KEY");
|
||||
assertNotNull(emailSubjectKey);
|
||||
assertEquals(msg.getSubject(), I18NUtil.getMessage(emailSubjectKey));
|
||||
|
||||
// Try the old credential
|
||||
TestHelper.assertThrows(() -> authenticateUser(testPerson2.userName, testPerson2.password),
|
||||
AuthenticationException.class,
|
||||
"As the user changed her password, the authentication should have failed.");
|
||||
|
||||
// Try the new credential
|
||||
authenticateUser(testPerson2.userName, "strongPassword");
|
||||
|
||||
// Make sure to run as system
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
AuthenticationUtil.setRunAsUserSystem();
|
||||
emailUtil.reset();
|
||||
// Try reset again with the used workflow
|
||||
TestHelper.assertThrows(() -> resetPasswordService.initiateResetPassword(passwordDetails),
|
||||
InvalidResetPasswordWorkflowException.class,
|
||||
"The workflow instance is not active (it has already been used).");
|
||||
assertEquals("No email should have been sent.", 0, emailUtil.getSentCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateResetPasswordUrl()
|
||||
{
|
||||
/* Out of the box we have share and workspace registered as the clients.
|
||||
* See: alfresco/client/config/repo-clients-apps.properties file.
|
||||
*/
|
||||
|
||||
// Share client
|
||||
ClientApp share = clientAppConfig.getClient("share");
|
||||
String shareResetPasswordUrl =
|
||||
resetPasswordService.createResetPasswordUrl(share, "workflow-id-123", "workflow-key-123");
|
||||
String shareExpectedUrl = UrlUtil.getShareUrl(sysAdminParams)
|
||||
+ "/page/reset-password?key=workflow-key-123&id=activiti$workflow-id-123";
|
||||
assertEquals(shareExpectedUrl, shareResetPasswordUrl);
|
||||
|
||||
// Workspace client
|
||||
ClientApp workspace = clientAppConfig.getClient("workspace");
|
||||
String workspaceResetPasswordUrl =
|
||||
resetPasswordService.createResetPasswordUrl(workspace, "workflow-id-456", "workflow-key-456");
|
||||
String workspaceExpectedUrl = UrlUtil.getAlfrescoBaseUrl(sysAdminParams)
|
||||
+ "/workspace/reset-password?key=workflow-key-456&id=activiti$workflow-id-456";
|
||||
assertEquals(workspaceExpectedUrl, workspaceResetPasswordUrl);
|
||||
}
|
||||
|
||||
private boolean isActive(String workflowId)
|
||||
{
|
||||
WorkflowInstance workflowInstance = workflowService.getWorkflowById(workflowId);
|
||||
|
||||
@@ -31,8 +31,8 @@ services:
|
||||
ports:
|
||||
- 8090:8090
|
||||
volumes:
|
||||
- ${CI_WORKSPACE}/keystores/tengineAIO/tengineAIO.truststore:/tengineAIO.truststore
|
||||
- ${CI_WORKSPACE}/keystores/tengineAIO/tengineAIO.keystore:/tengineAIO.keystore
|
||||
- ${GITHUB_WORKSPACE}/keystores/tengineAIO/tengineAIO.truststore:/tengineAIO.truststore
|
||||
- ${GITHUB_WORKSPACE}/keystores/tengineAIO/tengineAIO.keystore:/tengineAIO.keystore
|
||||
environment:
|
||||
ACTIVEMQ_URL: "nio://activemq:61616"
|
||||
ACTIVEMQ_USER: "admin"
|
||||
|
||||
27
scripts/ci/generate_keystores.sh
Normal file
27
scripts/ci/generate_keystores.sh
Normal file
@@ -0,0 +1,27 @@
|
||||
#! /bin/bash
|
||||
#! /bin/bash
|
||||
|
||||
# SETTINGS
|
||||
# Alfresco Format: "classic" / "current" is supported only from 7.0
|
||||
ALFRESCO_FORMAT=current
|
||||
|
||||
#Contains directory settings
|
||||
source ${GITHUB_WORKSPACE}/alfresco-ssl-generator/ssl-tool/utils.sh
|
||||
|
||||
# Cleanup previous output of script
|
||||
rm -rd $CA_DIR
|
||||
rm -rd $KEYSTORES_DIR
|
||||
rm -rd $CERTIFICATES_DIR
|
||||
|
||||
# SETTINGS
|
||||
# Alfresco Format: "classic" / "current" is supported only from 7.0
|
||||
ALFRESCO_FORMAT=current
|
||||
|
||||
#CA
|
||||
${GITHUB_WORKSPACE}/alfresco-ssl-generator/ssl-tool/run_ca.sh -keysize 2048 -keystorepass password -certdname "/C=GB/ST=UK/L=Maidenhead/O=Alfresco Software Ltd./OU=Unknown/CN=Custom Alfresco CA" -servername localhost -validityduration 1
|
||||
#Alfresco
|
||||
${GITHUB_WORKSPACE}/alfresco-ssl-generator/ssl-tool/run_additional.sh -servicename alfresco -rootcapass password -keysize 2048 -keystoretype JCEKS -keystorepass password -truststoretype JCEKS -truststorepass password -certdname "/C=GB/ST=UK/L=Maidenhead/O=Alfresco Software Ltd./OU=Unknown/CN=Custom Alfresco Repository" -servername localhost -alfrescoformat $ALFRESCO_FORMAT
|
||||
#Alfresco Metadata encryption
|
||||
${GITHUB_WORKSPACE}/alfresco-ssl-generator/ssl-tool/run_encryption.sh -subfoldername alfresco -servicename encryption -encstorepass mp6yc0UD9e -encmetadatapass oKIWzVdEdA -alfrescoformat $ALFRESCO_FORMAT
|
||||
#T-Engine AIO
|
||||
${GITHUB_WORKSPACE}/alfresco-ssl-generator/ssl-tool/run_additional.sh -servicename tengineAIO -rootcapass password -keysize 2048 -keystoretype JCEKS -keystorepass password -truststoretype JCEKS -truststorepass password -certdname "/C=GB/ST=UK/L=Maidenhead/O=Alfresco Software Ltd./OU=Unknown/CN=T-Engine AIO" -servername localhost -alfrescoformat $ALFRESCO_FORMAT
|
||||
Reference in New Issue
Block a user