mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-22 15:12:38 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
204dab1507 | ||
|
|
e7967bfe9e | ||
|
|
d8296d4049 | ||
|
|
e5bbb16360 | ||
|
|
0e82e519ac | ||
|
|
43c0fafe0d | ||
|
|
717d412159 | ||
|
|
5091f6c2e8 | ||
|
|
88c4a933ff | ||
|
|
c5d171135b | ||
|
|
fad5f7d20e | ||
|
|
3cd6b493d5 | ||
|
|
9309f2ab99 | ||
|
|
07fd5e8389 | ||
|
|
bdf32bffed | ||
|
|
f915e08b3d | ||
|
|
fab4d497e0 | ||
|
|
76c21e7102 | ||
|
|
a855fd7805 | ||
|
|
eef63bd242 | ||
|
|
d9d37470b5 | ||
|
|
817a89dd6c | ||
|
|
1e55a06512 | ||
|
|
ad52aac0a4 | ||
|
|
535651a682 | ||
|
|
9e14db2ee6 | ||
|
|
2652cdaa98 | ||
|
|
b595e41095 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -145,7 +145,7 @@ jobs:
|
||||
- uses: Alfresco/alfresco-build-tools/.github/actions/get-build-info@v8.16.0
|
||||
- uses: Alfresco/alfresco-build-tools/.github/actions/free-hosted-runner-disk-space@v8.16.0
|
||||
- uses: Alfresco/alfresco-build-tools/.github/actions/setup-java-build@v8.16.0
|
||||
- uses: Alfresco/ya-pmd-scan@v4.3.0
|
||||
- uses: Alfresco/ya-pmd-scan@v4.1.0
|
||||
with:
|
||||
classpath-build-command: "mvn test-compile -ntp -Pags -pl \"-:alfresco-community-repo-docker\""
|
||||
|
||||
|
||||
@@ -1273,7 +1273,7 @@
|
||||
"filename": "repository/src/main/resources/alfresco/repository.properties",
|
||||
"hashed_secret": "84551ae5442affc9f1a2d3b4c86ae8b24860149d",
|
||||
"is_verified": false,
|
||||
"line_number": 771,
|
||||
"line_number": 770,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
@@ -1539,7 +1539,7 @@
|
||||
"filename": "repository/src/test/java/org/alfresco/repo/rendition2/AbstractRenditionIntegrationTest.java",
|
||||
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
|
||||
"is_verified": false,
|
||||
"line_number": 130,
|
||||
"line_number": 127,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
@@ -1627,7 +1627,7 @@
|
||||
"filename": "repository/src/test/java/org/alfresco/repo/security/authentication/identityservice/SpringBasedIdentityServiceFacadeUnitTest.java",
|
||||
"hashed_secret": "5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8",
|
||||
"is_verified": false,
|
||||
"line_number": 48,
|
||||
"line_number": 46,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
@@ -1888,5 +1888,5 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"generated_at": "2025-05-15T21:47:13Z"
|
||||
"generated_at": "2024-10-09T09:32:52Z"
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -45,7 +45,7 @@ import com.github.dockerjava.netty.NettyDockerCmdExecFactory;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.alfresco.utility.Utility;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.apache.commons.lang.SystemUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@@ -26,6 +26,13 @@
|
||||
*/
|
||||
package org.alfresco.rest.rm.community.hold;
|
||||
|
||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
|
||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
|
||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
|
||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
|
||||
import static org.alfresco.utility.report.log.Step.STEP;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@@ -37,25 +44,12 @@ import static org.springframework.http.HttpStatus.NOT_FOUND;
|
||||
import static org.springframework.http.HttpStatus.OK;
|
||||
import static org.springframework.http.HttpStatus.UNAUTHORIZED;
|
||||
|
||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_DESCRIPTION;
|
||||
import static org.alfresco.rest.rm.community.base.TestData.HOLD_REASON;
|
||||
import static org.alfresco.rest.rm.community.model.fileplancomponents.FilePlanComponentAlias.FILE_PLAN_ALIAS;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_FILING;
|
||||
import static org.alfresco.rest.rm.community.model.user.UserPermissions.PERMISSION_READ_RECORDS;
|
||||
import static org.alfresco.rest.rm.community.util.CommonTestUtils.generateTestPrefix;
|
||||
import static org.alfresco.utility.report.log.Step.STEP;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import org.alfresco.dataprep.CMISUtil;
|
||||
import org.alfresco.dataprep.ContentActions;
|
||||
import org.alfresco.rest.rm.community.base.BaseRMRestTest;
|
||||
@@ -77,6 +71,10 @@ import org.alfresco.utility.constants.UserRole;
|
||||
import org.alfresco.utility.model.FileModel;
|
||||
import org.alfresco.utility.model.FolderModel;
|
||||
import org.alfresco.utility.model.UserModel;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* API tests for adding items to holds via the bulk process
|
||||
@@ -105,8 +103,7 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
STEP("Create a hold.");
|
||||
hold = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(),
|
||||
FILE_PLAN_ALIAS);
|
||||
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
|
||||
holds.add(hold);
|
||||
|
||||
STEP("Create test files.");
|
||||
@@ -134,23 +131,15 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
.until(() -> getRestAPIFactory().getSearchAPI(null).search(searchRequest).getPagination()
|
||||
.getTotalItems() == NUMBER_OF_FILES);
|
||||
|
||||
RestRequestQueryModel ancestorReq = getContentFromFolderAndAllSubfoldersQuery(rootFolder.getNodeRefWithoutVersion());
|
||||
SearchRequest ancestorSearchRequest = new SearchRequest();
|
||||
ancestorSearchRequest.setQuery(ancestorReq);
|
||||
|
||||
STEP("Wait until paths are indexed.");
|
||||
// to improve stability on CI - seems that sometimes during big load we need to wait longer for the condition
|
||||
await().atMost(120, TimeUnit.SECONDS)
|
||||
.until(() -> getRestAPIFactory().getSearchAPI(null).search(ancestorSearchRequest).getPagination()
|
||||
.getTotalItems() == NUMBER_OF_FILES);
|
||||
|
||||
holdBulkOperation = HoldBulkOperation.builder()
|
||||
.query(queryReq)
|
||||
.op(HoldBulkOperationType.ADD).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API Then the content is added to the hold and the status of the bulk operation is DONE
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then the content is added to the hold and the status of the bulk operation is DONE
|
||||
*/
|
||||
@Test
|
||||
public void addContentFromTestSiteToHoldUsingBulkAPI()
|
||||
@@ -169,11 +158,11 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
|
||||
STEP("Wait until all files are added to the hold.");
|
||||
await().atMost(20, TimeUnit.SECONDS).until(
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold.getId()).getEntries().size() == NUMBER_OF_FILES);
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold.getId()).getEntries().size()
|
||||
== NUMBER_OF_FILES);
|
||||
List<String> holdChildrenNodeRefs = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getChildren(hold.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
|
||||
HoldChild::getId)
|
||||
.toList();
|
||||
HoldChild::getId).toList();
|
||||
assertEquals(addedFiles.stream().map(FileModel::getNodeRefWithoutVersion).sorted().toList(),
|
||||
holdChildrenNodeRefs.stream().sorted().toList());
|
||||
|
||||
@@ -190,15 +179,16 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a folder and all subfolders to a hold using the bulk API Then the content is added to the hold and the status of the bulk operation is DONE
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a folder and all subfolders to a hold using the bulk API
|
||||
* Then the content is added to the hold and the status of the bulk operation is DONE
|
||||
*/
|
||||
@Test
|
||||
public void addContentFromFolderAndAllSubfoldersToHoldUsingBulkAPI()
|
||||
{
|
||||
hold3 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(),
|
||||
FILE_PLAN_ALIAS);
|
||||
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
|
||||
holds.add(hold3);
|
||||
|
||||
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
@@ -219,11 +209,11 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
|
||||
STEP("Wait until all files are added to the hold.");
|
||||
await().atMost(20, TimeUnit.SECONDS).until(
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold3.getId()).getEntries().size() == NUMBER_OF_FILES);
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold3.getId()).getEntries().size()
|
||||
== NUMBER_OF_FILES);
|
||||
List<String> holdChildrenNodeRefs = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getChildren(hold3.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
|
||||
HoldChild::getId)
|
||||
.toList();
|
||||
HoldChild::getId).toList();
|
||||
assertEquals(addedFiles.stream().map(FileModel::getNodeRefWithoutVersion).sorted().toList(),
|
||||
holdChildrenNodeRefs.stream().sorted().toList());
|
||||
|
||||
@@ -240,13 +230,16 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user without the add to hold capability When the user adds content from a site to a hold using the bulk API Then the user receives access denied error
|
||||
* Given a user without the add to hold capability
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then the user receives access denied error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessWithUserWithoutAddToHoldCapability()
|
||||
{
|
||||
UserModel userWithoutAddToHoldCapability = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
UserRole.SiteCollaborator,
|
||||
UserRole
|
||||
.SiteCollaborator,
|
||||
hold.getId(), UserRoles.ROLE_RM_POWER_USER, PERMISSION_FILING);
|
||||
users.add(userWithoutAddToHoldCapability);
|
||||
|
||||
@@ -260,7 +253,9 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user without the filing permission on a hold When the user adds content from a site to a hold using the bulk API Then the user receives access denied error
|
||||
* Given a user without the filing permission on a hold
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then the user receives access denied error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessWithUserWithoutFilingPermissionOnAHold()
|
||||
@@ -281,7 +276,9 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user without the write permission on all the content When the user adds content from a site to a hold using the bulk API Then all processed items are marked as errors and the last error message contains access denied error
|
||||
* Given a user without the write permission on all the content
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then all processed items are marked as errors and the last error message contains access denied error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessWithUserWithoutWritePermissionOnTheContent()
|
||||
@@ -306,7 +303,8 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
STEP("Verify the response.");
|
||||
assertStatusCode(ACCEPTED);
|
||||
|
||||
await().atMost(20, TimeUnit.SECONDS).until(() -> Objects.equals(getRestAPIFactory().getHoldsAPI(userWithoutPermission)
|
||||
await().atMost(20, TimeUnit.SECONDS).until(() ->
|
||||
Objects.equals(getRestAPIFactory().getHoldsAPI(userWithoutPermission)
|
||||
.getBulkStatus(hold.getId(), bulkOperationEntry.getBulkStatusId()).getStatus(), "DONE"));
|
||||
|
||||
HoldBulkStatus holdBulkStatus = getRestAPIFactory().getHoldsAPI(userWithoutPermission)
|
||||
@@ -316,15 +314,17 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user without the write permission on one file When the user adds content from a site to a hold using the bulk API Then all processed items are added to the hold except the one that the user does not have write permission And the status of the bulk operation is DONE, contains the error message and the number of errors is 1
|
||||
* Given a user without the write permission on one file
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then all processed items are added to the hold except the one that the user does not have write permission
|
||||
* And the status of the bulk operation is DONE, contains the error message and the number of errors is 1
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessWithUserWithoutWritePermissionOnOneFile()
|
||||
{
|
||||
hold2 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(),
|
||||
FILE_PLAN_ALIAS);
|
||||
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
|
||||
holds.add(hold2);
|
||||
|
||||
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
@@ -345,14 +345,15 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
|
||||
STEP("Wait until all files are added to the hold.");
|
||||
await().atMost(30, TimeUnit.SECONDS).until(
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold2.getId()).getEntries().size() == NUMBER_OF_FILES - 1);
|
||||
() -> getRestAPIFactory().getHoldsAPI(getAdminUser()).getChildren(hold2.getId()).getEntries().size()
|
||||
== NUMBER_OF_FILES - 1);
|
||||
await().atMost(30, TimeUnit.SECONDS).until(
|
||||
() -> getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getBulkStatus(hold2.getId(), bulkOperationEntry.getBulkStatusId()).getProcessedItems() == NUMBER_OF_FILES);
|
||||
.getBulkStatus(hold2.getId(), bulkOperationEntry.getBulkStatusId()).getProcessedItems()
|
||||
== NUMBER_OF_FILES);
|
||||
List<String> holdChildrenNodeRefs = getRestAPIFactory().getHoldsAPI(userAddHoldPermission)
|
||||
.getChildren(hold2.getId()).getEntries().stream().map(HoldChildEntry::getEntry).map(
|
||||
HoldChild::getId)
|
||||
.toList();
|
||||
HoldChild::getId).toList();
|
||||
assertEquals(addedFiles.stream().skip(1).map(FileModel::getNodeRefWithoutVersion).sorted().toList(),
|
||||
holdChildrenNodeRefs.stream().sorted().toList());
|
||||
|
||||
@@ -374,7 +375,9 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an unauthenticated user When the user adds content from a site to a hold using the bulk API Then the user receives unauthorized error
|
||||
* Given an unauthenticated user
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* Then the user receives unauthorized error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessAsUnauthenticatedUser()
|
||||
@@ -388,7 +391,10 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And the hold does not exist Then the user receives not found error
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And the hold does not exist
|
||||
* Then the user receives not found error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessForNonExistentHold()
|
||||
@@ -401,7 +407,10 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API and the bulk operation is invalid Then the user receives bad request error
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* and the bulk operation is invalid
|
||||
* Then the user receives bad request error
|
||||
*/
|
||||
@Test
|
||||
public void testGetBulkStatusesForInvalidOperation()
|
||||
@@ -417,7 +426,10 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And the hold does not exist Then the user receives not found error
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And the hold does not exist
|
||||
* Then the user receives not found error
|
||||
*/
|
||||
@Test
|
||||
public void testGetBulkStatusForNonExistentHold()
|
||||
@@ -430,7 +442,10 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And the bulk status does not exist Then the user receives not found error
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And the bulk status does not exist
|
||||
* Then the user receives not found error
|
||||
*/
|
||||
@Test
|
||||
public void testGetBulkStatusForNonExistentBulkStatus()
|
||||
@@ -443,7 +458,10 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And the hold does not exist Then the user receives not found error
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And the hold does not exist
|
||||
* Then the user receives not found error
|
||||
*/
|
||||
@Test
|
||||
public void testGetBulkStatusesForNonExistentHold()
|
||||
@@ -456,7 +474,9 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from all sites to a hold using the bulk API to exceed the limit (30 items) Then the user receives bad request error
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from all sites to a hold using the bulk API to exceed the limit (30 items)
|
||||
* Then the user receives bad request error
|
||||
*/
|
||||
@Test
|
||||
public void testExceedingBulkOperationLimit()
|
||||
@@ -477,15 +497,17 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And then the user cancels the bulk operation Then the user receives OK status code
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And then the user cancels the bulk operation
|
||||
* Then the user receives OK status code
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessCancellationWithAllowedUser()
|
||||
{
|
||||
Hold hold4 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(),
|
||||
FILE_PLAN_ALIAS);
|
||||
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
|
||||
holds.add(hold4);
|
||||
|
||||
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
@@ -509,15 +531,17 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a user with the add to hold capability and hold filing permission When the user adds content from a site to a hold using the bulk API And a 2nd user without the add to hold capability cancels the bulk operation Then the 2nd user receives access denied error
|
||||
* Given a user with the add to hold capability and hold filing permission
|
||||
* When the user adds content from a site to a hold using the bulk API
|
||||
* And a 2nd user without the add to hold capability cancels the bulk operation
|
||||
* Then the 2nd user receives access denied error
|
||||
*/
|
||||
@Test
|
||||
public void testBulkProcessCancellationWithUserWithoutAddToHoldCapability()
|
||||
{
|
||||
Hold hold5 = getRestAPIFactory().getFilePlansAPI(getAdminUser()).createHold(
|
||||
Hold.builder().name("HOLD" + generateTestPrefix(AddToHoldsV1Tests.class)).description(HOLD_DESCRIPTION)
|
||||
.reason(HOLD_REASON).build(),
|
||||
FILE_PLAN_ALIAS);
|
||||
.reason(HOLD_REASON).build(), FILE_PLAN_ALIAS);
|
||||
holds.add(hold5);
|
||||
|
||||
UserModel userAddHoldPermission = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
@@ -533,7 +557,8 @@ public class AddToHoldsBulkV1Tests extends BaseRMRestTest
|
||||
assertEquals(NUMBER_OF_FILES, bulkOperationEntry.getTotalItems());
|
||||
|
||||
UserModel userWithoutAddToHoldCapability = roleService.createUserWithSiteRoleRMRoleAndPermission(testSite,
|
||||
UserRole.SiteCollaborator,
|
||||
UserRole
|
||||
.SiteCollaborator,
|
||||
hold5.getId(), UserRoles.ROLE_RM_POWER_USER, PERMISSION_FILING);
|
||||
users.add(userWithoutAddToHoldCapability);
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.alfresco.rest.v0.RMRolesAndActionsAPI;
|
||||
import org.alfresco.rest.v0.RecordsAPI;
|
||||
import org.alfresco.rest.v0.RecordCategoriesAPI;
|
||||
import org.alfresco.test.AlfrescoTest;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@@ -44,7 +44,7 @@ import org.alfresco.rest.v0.service.DispositionScheduleService;
|
||||
import org.alfresco.test.AlfrescoTest;
|
||||
import org.alfresco.utility.model.RepoTestModel;
|
||||
import org.alfresco.utility.model.UserModel;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
|
||||
@@ -23,7 +23,7 @@ Recorded content can be explicitly destroyed whilst maintaining the original nod
|
||||
* License: Alfresco Community
|
||||
* Issue Tracker Link: [JIRA RM](https://issues.alfresco.com/jira/projects/RM/summary)
|
||||
* Contribution Model: Alfresco Closed Source
|
||||
* Documentation: [docs.alfresco.com (Records Management)](https://support.hyland.com/r/Alfresco/Alfresco-Governance-Services-Community-Edition/23.4/Alfresco-Governance-Services-Community-Edition/Introduction)
|
||||
* Documentation: [docs.alfresco.com (Records Management)](http://docs.alfresco.com/rm2.4/concepts/welcome-rm.html)
|
||||
|
||||
***
|
||||
|
||||
|
||||
@@ -21,18 +21,18 @@ RM is split into two main parts - a repository integration and a Share integrati
|
||||
* [Community License](../LICENSE.txt)
|
||||
* [Enterprise License](../../rm-enterprise/LICENSE.txt) (this file will only be present in clones of the Enterprise repository)
|
||||
* [Issue Tracker Link](https://issues.alfresco.com/jira/projects/RM)
|
||||
* [Community Documentation Link](https://support.hyland.com/r/Alfresco/Alfresco-Governance-Services-Community-Edition/23.4/Alfresco-Governance-Services-Community-Edition/Introduction)
|
||||
* [Enterprise Documentation Link](https://support.hyland.com/r/Alfresco/Alfresco-Governance-Services/23.4/Alfresco-Governance-Services/Introduction)
|
||||
* [Community Documentation Link](http://docs.alfresco.com/rm-community/concepts/welcome-rm.html)
|
||||
* [Enterprise Documentation Link](http://docs.alfresco.com/rm/concepts/welcome-rm.html)
|
||||
* [Contribution Model](../../CONTRIBUTING.md)
|
||||
|
||||
***
|
||||
|
||||
### Prerequisite Knowledge
|
||||
An understanding of Alfresco Content Services is assumed. The following pages from the [developer documentation](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services-Community-Edition/23.4/Alfresco-Content-Services-Community-Edition/Develop) give useful background information:
|
||||
An understanding of Alfresco Content Services is assumed. The following pages from the [developer documentation](http://docs.alfresco.com/5.2/concepts/dev-for-developers.html) give useful background information:
|
||||
|
||||
* [ACS Architecture](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/Software-Architecture)
|
||||
* [Platform Extensions](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/Extension-Points-Overview)
|
||||
* [Share Extensions](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/Share-UI-Extension-Points)
|
||||
* [ACS Architecture](http://docs.alfresco.com/5.2/concepts/dev-arch-overview.html)
|
||||
* [Platform Extensions](http://docs.alfresco.com/5.2/concepts/dev-platform-extensions.html)
|
||||
* [Share Extensions](http://docs.alfresco.com/5.2/concepts/dev-extensions-share.html)
|
||||
|
||||
***
|
||||
|
||||
@@ -44,12 +44,12 @@ The RM Share module communicates with the repository module via REST APIs. Inter
|
||||
* A DAO layer responsible for CRUD operations against the database.
|
||||
|
||||
#### REST API
|
||||
The REST API endpoints fall into two main types - v0 (Webscripts) and v1. The [v0 API](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/In-Process-Platform-Extension-Points/Web-Scripts) is older and not recommended for integrations. The [v1 API](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/REST-API-Guide) is newer but isn't yet feature complete. If you are running RM locally then the GS API Explorer will be available at [this link](http://localhost:8080/gs-api-explorer/).
|
||||
The REST API endpoints fall into two main types - v0 (Webscripts) and v1. The [v0 API](http://docs.alfresco.com/5.2/references/dev-extension-points-webscripts.html) is older and not recommended for integrations. The [v1 API](http://docs.alfresco.com/5.1/pra/1/topics/pra-welcome-aara.html) is newer but isn't yet feature complete. If you are running RM locally then the GS API Explorer will be available at [this link](http://localhost:8080/gs-api-explorer/).
|
||||
|
||||
Internally the GS v1 REST API is built on the [Alfresco v1 REST API framework](https://community.alfresco.com/community/ecm/blog/2016/10/11/v1-rest-api-part-1-introduction). It aims to be consistent with this in terms of behaviour and naming.
|
||||
|
||||
#### Java Public API
|
||||
The Java service layer is fronted by a [Java Public API](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/Reference/Java-Foundation-API), which we will ensure backward compatible with previous releases. Before we remove any methods there will first be a release containing that method deprecated to allow third party integrations to migrate to a new method. The Java Public API also includes a set of POJO objects which are needed to communicate with the services. It is easy to identify classes that are part of the Java Public API as they are annotated `@AlfrescoPublicApi`.
|
||||
The Java service layer is fronted by a [Java Public API](http://docs.alfresco.com/5.2/concepts/java-public-api-list.html), which we will ensure backward compatible with previous releases. Before we remove any methods there will first be a release containing that method deprecated to allow third party integrations to migrate to a new method. The Java Public API also includes a set of POJO objects which are needed to communicate with the services. It is easy to identify classes that are part of the Java Public API as they are annotated `@AlfrescoPublicApi`.
|
||||
|
||||
Each Java service will have at least four beans defined for it:
|
||||
|
||||
@@ -61,7 +61,7 @@ Each Java service will have at least four beans defined for it:
|
||||
#### DAOs
|
||||
The DAOs are not part of the Java Public API, but handle CRUD operations against RM stored data. We have some custom queries to improve performance for particularly heavy operations.
|
||||
|
||||
We use standard Alfresco [data modelling](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/In-Process-Platform-Extension-Points/Content-Model-Extension-Point) to store RM metadata. We extend the [Alfresco patching mechanism](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/In-Process-Platform-Extension-Points/Patches) to provide community and enterprise schema upgrades.
|
||||
We use standard Alfresco [data modelling](http://docs.alfresco.com/5.2/references/dev-extension-points-content-model.html) to store RM metadata. We extend the [Alfresco patching mechanism](http://docs.alfresco.com/5.2/references/dev-extension-points-patch.html) to provide community and enterprise schema upgrades.
|
||||
|
||||
***
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
SOLR6_TAG=2.0.17
|
||||
SOLR6_TAG=2.0.13
|
||||
POSTGRES_TAG=15.4
|
||||
ACTIVEMQ_TAG=5.18.3-jre17-rockylinux8
|
||||
|
||||
@@ -119,11 +119,6 @@ rm.patch.v35.holdNewChildAssocPatch.batchSize=1000
|
||||
rm.haspermissionmap.read=Read
|
||||
rm.haspermissionmap.write=WriteProperties,AddChildren,ReadContent
|
||||
|
||||
# Extended Permissions
|
||||
# Enable matching the given username with the correct casing username when retrieving an IPR group.
|
||||
# Only needs to be used if there are owners that don't have the username in the correct casing.
|
||||
rm.extendedSecurity.enableUsernameNormalization=false
|
||||
|
||||
#
|
||||
# Extended auto-version behaviour. If true and other auto-version properties are satisfied, then
|
||||
# a document will be auto-versioned when its type is changed.
|
||||
|
||||
@@ -34,7 +34,4 @@
|
||||
<!-- content cleanser -->
|
||||
<bean id="contentCleanser.522022M" class="org.alfresco.module.org_alfresco_module_rm.content.cleanser.ContentCleanser522022M"/>
|
||||
|
||||
<!-- content cleanser -->
|
||||
<bean id="contentCleanser.SevenPass" class="org.alfresco.module.org_alfresco_module_rm.content.cleanser.ContentCleanserSevenPass"/>
|
||||
|
||||
</beans>
|
||||
|
||||
@@ -15,13 +15,6 @@
|
||||
<parameter property="end" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
</parameterMap>
|
||||
|
||||
<parameterMap id="parameter_NodeIdsWhichReferenceContentUrl" type="map">
|
||||
<parameter property="contentUrlShort" jdbcType="VARCHAR" javaType="java.lang.String"/>
|
||||
<parameter property="contentUrlCrc" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<parameter property="localName" jdbcType="VARCHAR" javaType="java.lang.String"/>
|
||||
<parameter property="uri" jdbcType="VARCHAR" javaType="java.lang.String"/>
|
||||
</parameterMap>
|
||||
|
||||
<resultMap id="result_NodeRefEntity" type="org.alfresco.module.org_alfresco_module_rm.query.NodeRefEntity">
|
||||
<result property="row" column="row" jdbcType="BIGINT" javaType="java.lang.Long"/>
|
||||
<result property="protocol" column="protocol" jdbcType="VARCHAR" javaType="java.lang.String"/>
|
||||
@@ -62,21 +55,18 @@
|
||||
|
||||
<!-- Get list of node ids which reference given content url -->
|
||||
<select id="select_NodeIdsWhichReferenceContentUrl"
|
||||
parameterMap="parameter_NodeIdsWhichReferenceContentUrl"
|
||||
parameterType="ContentUrl"
|
||||
resultMap="result_NodeIds">
|
||||
select
|
||||
p.node_id
|
||||
from
|
||||
alf_content_url cu
|
||||
left outer join alf_content_data cd ON (cd.content_url_id = cu.id)
|
||||
left outer join alf_node_properties p ON (p.long_value = cd.id)
|
||||
left outer join alf_qname q ON (q.id = p.qname_id)
|
||||
left outer join alf_namespace n ON (n.id = q.ns_id)
|
||||
where
|
||||
cu.content_url_short = ? and
|
||||
cu.content_url_crc = ? and
|
||||
q.local_name = ? and
|
||||
n.uri = ?
|
||||
LEFT OUTER JOIN alf_content_data cd ON (cd.content_url_id = cu.id)
|
||||
LEFT OUTER JOIN alf_node_properties p ON (p.long_value = cd.id)
|
||||
WHERE
|
||||
content_url_short = #{contentUrlShort} and
|
||||
content_url_crc = #{contentUrlCrc}
|
||||
|
||||
</select>
|
||||
|
||||
<select id="select_RecordFoldersWithSchedules"
|
||||
|
||||
@@ -611,7 +611,6 @@
|
||||
<property name="authorityService" ref="authorityService"/>
|
||||
<property name="permissionService" ref="permissionService"/>
|
||||
<property name="transactionService" ref="transactionService"/>
|
||||
<property name="enableUsernameNormalization" value="${rm.extendedSecurity.enableUsernameNormalization}" />
|
||||
</bean>
|
||||
|
||||
<bean id="ExtendedSecurityService" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* -
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
* -
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* -
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* -
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
package org.alfresco.module.org_alfresco_module_rm.content.cleanser;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* DoD 5220-22M Seven Pass data cleansing implementation.
|
||||
*
|
||||
*/
|
||||
public class ContentCleanserSevenPass extends ContentCleanser522022M
|
||||
{
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.content.cleanser.ContentCleanser#cleanse(java.io.File)
|
||||
*/
|
||||
@Override
|
||||
public void cleanse(File file)
|
||||
{
|
||||
super.cleanse(file);
|
||||
overwrite(file, overwriteZeros);
|
||||
overwrite(file, overwriteZeros);
|
||||
overwrite(file, overwriteOnes);
|
||||
overwrite(file, overwriteRandom);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
package org.alfresco.module.org_alfresco_module_rm.query;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -35,11 +36,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.model.RecordsManagementModel;
|
||||
import org.alfresco.repo.domain.contentdata.ContentUrlEntity;
|
||||
import org.alfresco.repo.domain.node.NodeDAO;
|
||||
@@ -51,6 +47,9 @@ import org.alfresco.service.cmr.repository.InvalidNodeRefException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.mybatis.spring.SqlSessionTemplate;
|
||||
|
||||
/**
|
||||
* Records management query DAO implementation
|
||||
@@ -90,8 +89,7 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
|
||||
protected TenantService tenantService;
|
||||
|
||||
/**
|
||||
* @param sqlSessionTemplate
|
||||
* SQL session template
|
||||
* @param sqlSessionTemplate SQL session template
|
||||
*/
|
||||
public final void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate)
|
||||
{
|
||||
@@ -99,8 +97,7 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
|
||||
}
|
||||
|
||||
/**
|
||||
* @param qnameDAO
|
||||
* qname DAO
|
||||
* @param qnameDAO qname DAO
|
||||
*/
|
||||
public final void setQnameDAO(QNameDAO qnameDAO)
|
||||
{
|
||||
@@ -176,8 +173,7 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
|
||||
/**
|
||||
* Get a set of node reference which reference the provided content URL
|
||||
*
|
||||
* @param String
|
||||
* contentUrl content URL
|
||||
* @param String contentUrl content URL
|
||||
* @return Set<NodeRef> set of nodes that reference the provided content URL
|
||||
*/
|
||||
@Override
|
||||
@@ -192,19 +188,13 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
|
||||
ContentUrlEntity contentUrlEntity = new ContentUrlEntity();
|
||||
contentUrlEntity.setContentUrl(contentUrl.toLowerCase());
|
||||
|
||||
Map<String, Object> params = new HashMap<>(4);
|
||||
params.put("contentUrlShort", contentUrlEntity.getContentUrlShort());
|
||||
params.put("contentUrlCrc", contentUrlEntity.getContentUrlCrc());
|
||||
params.put("localName", ContentModel.PROP_CONTENT.getLocalName());
|
||||
params.put("uri", ContentModel.PROP_CONTENT.getNamespaceURI());
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("Executing query " + SELECT_NODE_IDS_WHICH_REFERENCE_CONTENT_URL);
|
||||
}
|
||||
|
||||
// Get all the node ids which reference the given content url
|
||||
List<Long> nodeIds = template.selectList(SELECT_NODE_IDS_WHICH_REFERENCE_CONTENT_URL, params);
|
||||
List<Long> nodeIds = template.selectList(SELECT_NODE_IDS_WHICH_REFERENCE_CONTENT_URL, contentUrlEntity);
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
{
|
||||
@@ -299,8 +289,7 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.query.RecordsManagementQueryDAO#getPropertyStringValueEntity(String stringValue)
|
||||
*/
|
||||
public PropertyStringValueEntity getPropertyStringValueEntity(String stringValue)
|
||||
{
|
||||
public PropertyStringValueEntity getPropertyStringValueEntity(String stringValue){
|
||||
|
||||
PropertyStringValueEntity propertyStringValueEntity = new PropertyStringValueEntity();
|
||||
propertyStringValueEntity.setValue(stringValue);
|
||||
|
||||
@@ -34,12 +34,6 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
import org.springframework.extensions.webscripts.ui.common.StringUtils;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
|
||||
@@ -48,10 +42,7 @@ import org.alfresco.module.org_alfresco_module_rm.role.FilePlanRoleService;
|
||||
import org.alfresco.module.org_alfresco_module_rm.util.ServiceBaseImpl;
|
||||
import org.alfresco.query.PagingRequest;
|
||||
import org.alfresco.query.PagingResults;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.security.authority.RMAuthority;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.DuplicateChildNodeNameException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
@@ -63,6 +54,12 @@ import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.extensions.webscripts.ui.common.StringUtils;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
|
||||
/**
|
||||
* Extended security service implementation.
|
||||
@@ -98,11 +95,8 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/** transaction service */
|
||||
private TransactionService transactionService;
|
||||
|
||||
private boolean enableUsernameNormalization;
|
||||
|
||||
/**
|
||||
* @param filePlanService
|
||||
* file plan service
|
||||
* @param filePlanService file plan service
|
||||
*/
|
||||
public void setFilePlanService(FilePlanService filePlanService)
|
||||
{
|
||||
@@ -110,8 +104,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filePlanRoleService
|
||||
* file plan role service
|
||||
* @param filePlanRoleService file plan role service
|
||||
*/
|
||||
public void setFilePlanRoleService(FilePlanRoleService filePlanRoleService)
|
||||
{
|
||||
@@ -119,8 +112,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* @param authorityService
|
||||
* authority service
|
||||
* @param authorityService authority service
|
||||
*/
|
||||
public void setAuthorityService(AuthorityService authorityService)
|
||||
{
|
||||
@@ -128,8 +120,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* @param permissionService
|
||||
* permission service
|
||||
* @param permissionService permission service
|
||||
*/
|
||||
public void setPermissionService(PermissionService permissionService)
|
||||
{
|
||||
@@ -137,23 +128,13 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transactionService
|
||||
* transaction service
|
||||
* @param transactionService transaction service
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
this.transactionService = transactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param enableUsernameNormalization
|
||||
* enable username normalization to ensure correct casing
|
||||
*/
|
||||
public void setEnableUsernameNormalization(boolean enableUsernameNormalization)
|
||||
{
|
||||
this.enableUsernameNormalization = enableUsernameNormalization;
|
||||
}
|
||||
|
||||
/**
|
||||
* Application context refresh event handler
|
||||
*/
|
||||
@@ -161,10 +142,12 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent)
|
||||
{
|
||||
// run as System on bootstrap
|
||||
AuthenticationUtil.runAs(new RunAsWork<Object>() {
|
||||
AuthenticationUtil.runAs(new RunAsWork<Object>()
|
||||
{
|
||||
public Object doWork()
|
||||
{
|
||||
RetryingTransactionCallback<Void> callback = new RetryingTransactionCallback<Void>() {
|
||||
RetryingTransactionCallback<Void> callback = new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute()
|
||||
{
|
||||
// if the root group doesn't exist then create it
|
||||
@@ -241,8 +224,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* Helper to get authorities for a given group
|
||||
*
|
||||
* @param group
|
||||
* group name
|
||||
* @param group group name
|
||||
* @return Set<String> immediate authorities
|
||||
*/
|
||||
private Set<String> getAuthorities(String group)
|
||||
@@ -302,8 +284,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
* <p>
|
||||
* Return null if none found.
|
||||
*
|
||||
* @param nodeRef
|
||||
* node reference
|
||||
* @param nodeRef node reference
|
||||
* @return Pair<String, String> where first is the read group and second if the write group, null if none found
|
||||
*/
|
||||
private Pair<String, String> getIPRGroups(NodeRef nodeRef)
|
||||
@@ -340,17 +321,17 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* Given a set of readers and writers find or create the appropriate IPR groups.
|
||||
* <p>
|
||||
* The IPR groups are named with hashes of the authority lists in order to reduce the set of groups that require exact match. A further index is used to handle a situation where there is a hash clash, but a difference in the authority lists.
|
||||
* The IPR groups are named with hashes of the authority lists in order to reduce
|
||||
* the set of groups that require exact match. A further index is used to handle
|
||||
* a situation where there is a hash clash, but a difference in the authority lists.
|
||||
* <p>
|
||||
* When no match is found the groups are created. Once created
|
||||
*
|
||||
* @param filePlan
|
||||
* file plan
|
||||
* @param readers
|
||||
* authorities with read
|
||||
* @param writers
|
||||
* authorities with write
|
||||
* @return Pair<String, String> where first is the full name of the read group and second is the full name of the write group
|
||||
* @param filePlan file plan
|
||||
* @param readers authorities with read
|
||||
* @param writers authorities with write
|
||||
* @return Pair<String, String> where first is the full name of the read group and
|
||||
* second is the full name of the write group
|
||||
*/
|
||||
private Pair<String, String> createOrFindIPRGroups(Set<String> readers, Set<String> writers)
|
||||
{
|
||||
@@ -362,28 +343,20 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* Create or find an IPR group based on the provided prefix and authorities.
|
||||
*
|
||||
* @param groupPrefix
|
||||
* group prefix
|
||||
* @param authorities
|
||||
* authorities
|
||||
* @param groupPrefix group prefix
|
||||
* @param authorities authorities
|
||||
* @return String full group name
|
||||
*/
|
||||
private String createOrFindIPRGroup(String groupPrefix, Set<String> authorities)
|
||||
{
|
||||
String group = null;
|
||||
|
||||
// If enabled, the authorities are forced to match the correct casing of the usernames in case they were set
|
||||
// with the incorrect casing.
|
||||
// If not, it will just use the authorities as they are.
|
||||
// In normal circumstances, the authorities are in the correct casing, so this is disabled by default.
|
||||
Set<String> authoritySet = normalizeAuthorities(authorities);
|
||||
|
||||
// find group or determine what the next index is if no group exists or there is a clash
|
||||
Pair<String, Integer> groupResult = findIPRGroup(groupPrefix, authoritySet);
|
||||
Pair<String, Integer> groupResult = findIPRGroup(groupPrefix, authorities);
|
||||
|
||||
if (groupResult.getFirst() == null)
|
||||
{
|
||||
group = createIPRGroup(groupPrefix, authoritySet, groupResult.getSecond());
|
||||
group = createIPRGroup(groupPrefix, authorities, groupResult.getSecond());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -396,13 +369,13 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* Given a group name prefix and the authorities, finds the exact match existing group.
|
||||
* <p>
|
||||
* If the group does not exist then the group returned is null and the index shows the next available group index for creation.
|
||||
* If the group does not exist then the group returned is null and the index shows the next available
|
||||
* group index for creation.
|
||||
*
|
||||
* @param groupPrefix
|
||||
* group name prefix
|
||||
* @param authorities
|
||||
* authorities
|
||||
* @return Pair<String, Integer> where first is the name of the found group, null if none found and second if the next available create index
|
||||
* @param groupPrefix group name prefix
|
||||
* @param authorities authorities
|
||||
* @return Pair<String, Integer> where first is the name of the found group, null if none found and second
|
||||
* if the next available create index
|
||||
*/
|
||||
private Pair<String, Integer> findIPRGroup(String groupPrefix, Set<String> authorities)
|
||||
{
|
||||
@@ -418,13 +391,12 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
while (hasMoreItems == true)
|
||||
{
|
||||
// get matching authorities
|
||||
PagingResults<String> results = authorityService.getAuthorities(
|
||||
AuthorityType.GROUP,
|
||||
PagingResults<String> results = authorityService.getAuthorities(AuthorityType.GROUP,
|
||||
RMAuthority.ZONE_APP_RM,
|
||||
groupShortNamePrefix,
|
||||
false,
|
||||
false,
|
||||
new PagingRequest(MAX_ITEMS * pageCount, MAX_ITEMS));
|
||||
new PagingRequest(MAX_ITEMS*pageCount, MAX_ITEMS));
|
||||
|
||||
// record the total count
|
||||
nextGroupIndex = nextGroupIndex + results.getPage().size();
|
||||
@@ -441,81 +413,22 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
|
||||
// determine if there are any more pages to inspect
|
||||
hasMoreItems = results.hasMoreItems();
|
||||
pageCount++;
|
||||
pageCount ++;
|
||||
}
|
||||
|
||||
return new Pair<>(iprGroup, nextGroupIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a set of authorities, normalizes the authority names to ensure correct casing.
|
||||
*
|
||||
* @param authNames
|
||||
* @return
|
||||
*/
|
||||
private Set<String> normalizeAuthorities(Set<String> authNames)
|
||||
{
|
||||
// If disabled or no authorities, return as is
|
||||
if (!enableUsernameNormalization || authNames == null || authNames.isEmpty())
|
||||
{
|
||||
return authNames;
|
||||
}
|
||||
|
||||
Set<String> normalizedAuthorities = new HashSet<>();
|
||||
for (String authorityName : authNames)
|
||||
{
|
||||
normalizedAuthorities.add(normalizeAuthorityName(authorityName));
|
||||
}
|
||||
return normalizedAuthorities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Usernames are case insensitive but affect the IPR group matching when set with different casing. For a given authority of type user, this method normalizes the authority name. If group, it returns the name as-is.
|
||||
*
|
||||
* @param authorityName
|
||||
* the authority name to normalize
|
||||
* @return the normalized authority name
|
||||
*/
|
||||
private String normalizeAuthorityName(String authorityName)
|
||||
{
|
||||
if (authorityName == null || authorityName.startsWith(GROUP_PREFIX))
|
||||
{
|
||||
return authorityName;
|
||||
}
|
||||
|
||||
// For users, attempt to get the correct casing from the username property of the user node
|
||||
if (authorityService.authorityExists(authorityName))
|
||||
{
|
||||
try
|
||||
{
|
||||
NodeRef authorityNodeRef = authorityService.getAuthorityNodeRef(authorityName);
|
||||
if (authorityNodeRef != null)
|
||||
{
|
||||
String username = (String) nodeService.getProperty(authorityNodeRef, ContentModel.PROP_USERNAME);
|
||||
return username != null ? username : authorityName;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// If anything goes wrong, fallback to the original name
|
||||
}
|
||||
}
|
||||
|
||||
return authorityName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a group exactly matches a list of authorities.
|
||||
*
|
||||
* @param authorities
|
||||
* list of authorities
|
||||
* @param group
|
||||
* group
|
||||
* @param authorities list of authorities
|
||||
* @param group group
|
||||
* @return
|
||||
*/
|
||||
private boolean isIPRGroupTrueMatch(String group, Set<String> authorities)
|
||||
{
|
||||
// Remove GROUP_EVERYONE for proper comparison as GROUP_EVERYONE is never included in an IPR group
|
||||
//Remove GROUP_EVERYONE for proper comparison as GROUP_EVERYONE is never included in an IPR group
|
||||
Set<String> plainAuthorities = new HashSet<String>();
|
||||
if (authorities != null)
|
||||
{
|
||||
@@ -531,13 +444,11 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
* <p>
|
||||
* 'package' scope to help testing.
|
||||
*
|
||||
* @param prefix
|
||||
* prefix
|
||||
* @param authorities
|
||||
* authorities
|
||||
* @param prefix prefix
|
||||
* @param authorities authorities
|
||||
* @return String group prefix short name
|
||||
*/
|
||||
/* package */ String getIPRGroupPrefixShortName(String prefix, Set<String> authorities)
|
||||
/*package*/ String getIPRGroupPrefixShortName(String prefix, Set<String> authorities)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(128)
|
||||
.append(prefix)
|
||||
@@ -553,17 +464,13 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
* <p>
|
||||
* 'package' scope to help testing.
|
||||
*
|
||||
* @param prefix
|
||||
* prefix
|
||||
* @param readers
|
||||
* read authorities
|
||||
* @param writers
|
||||
* write authorities
|
||||
* @param index
|
||||
* group index
|
||||
* @param prefix prefix
|
||||
* @param readers read authorities
|
||||
* @param writers write authorities
|
||||
* @param index group index
|
||||
* @return String group short name
|
||||
*/
|
||||
/* package */ String getIPRGroupShortName(String prefix, Set<String> authorities, int index)
|
||||
/*package*/ String getIPRGroupShortName(String prefix, Set<String> authorities, int index)
|
||||
{
|
||||
return getIPRGroupShortName(prefix, authorities, Integer.toString(index));
|
||||
}
|
||||
@@ -573,14 +480,10 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
* <p>
|
||||
* Note this excludes the "GROUP_" prefix.
|
||||
*
|
||||
* @param prefix
|
||||
* prefix
|
||||
* @param readers
|
||||
* read authorities
|
||||
* @param writers
|
||||
* write authorities
|
||||
* @param index
|
||||
* group index
|
||||
* @param prefix prefix
|
||||
* @param readers read authorities
|
||||
* @param writers write authorities
|
||||
* @param index group index
|
||||
* @return String group short name
|
||||
*/
|
||||
private String getIPRGroupShortName(String prefix, Set<String> authorities, String index)
|
||||
@@ -595,8 +498,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* Gets the hashcode value of a set of authorities.
|
||||
*
|
||||
* @param authorities
|
||||
* set of authorities
|
||||
* @param authorities set of authorities
|
||||
* @return int hash code
|
||||
*/
|
||||
private int getAuthoritySetHashCode(Set<String> authorities)
|
||||
@@ -612,12 +514,9 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* Creates a new IPR group.
|
||||
*
|
||||
* @param groupNamePrefix
|
||||
* group name prefix
|
||||
* @param children
|
||||
* child authorities
|
||||
* @param index
|
||||
* group index
|
||||
* @param groupNamePrefix group name prefix
|
||||
* @param children child authorities
|
||||
* @param index group index
|
||||
* @return String full name of created group
|
||||
*/
|
||||
private String createIPRGroup(String groupNamePrefix, Set<String> children, int index)
|
||||
@@ -648,10 +547,10 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (DuplicateChildNodeNameException ex)
|
||||
catch(DuplicateChildNodeNameException ex)
|
||||
{
|
||||
// Rethrow as ConcurrencyFailureException so that is can be retried and linked to the group created by the concurrent transaction
|
||||
throw new ConcurrencyFailureException("IPR group creation failed due to concurrent duplicate group name creation: " + groupShortName);
|
||||
// the group was concurrently created
|
||||
group = authorityService.getName(AuthorityType.GROUP, groupShortName);
|
||||
}
|
||||
|
||||
return group;
|
||||
@@ -660,10 +559,8 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* Assign IPR groups to a node reference with the correct permissions.
|
||||
*
|
||||
* @param iprGroups
|
||||
* iprGroups, first read and second write
|
||||
* @param nodeRef
|
||||
* node reference
|
||||
* @param iprGroups iprGroups, first read and second write
|
||||
* @param nodeRef node reference
|
||||
*/
|
||||
private void assignIPRGroupsToNode(Pair<String, String> iprGroups, NodeRef nodeRef)
|
||||
{
|
||||
@@ -701,8 +598,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* Clear the nodes IPR permissions
|
||||
*
|
||||
* @param nodeRef
|
||||
* node reference
|
||||
* @param nodeRef node reference
|
||||
*/
|
||||
private void clearPermissions(NodeRef nodeRef, Pair<String, String> iprGroups)
|
||||
{
|
||||
@@ -714,9 +610,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#getExtendedReaders(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public Set<String> getExtendedReaders(NodeRef nodeRef)
|
||||
@Override @Deprecated public Set<String> getExtendedReaders(NodeRef nodeRef)
|
||||
{
|
||||
return getReaders(nodeRef);
|
||||
}
|
||||
@@ -724,9 +618,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#getExtendedWriters(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public Set<String> getExtendedWriters(NodeRef nodeRef)
|
||||
@Override @Deprecated public Set<String> getExtendedWriters(NodeRef nodeRef)
|
||||
{
|
||||
return getWriters(nodeRef);
|
||||
}
|
||||
@@ -734,9 +626,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers)
|
||||
@Override @Deprecated public void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers)
|
||||
{
|
||||
set(nodeRef, readers, writers);
|
||||
}
|
||||
@@ -744,9 +634,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#addExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set, boolean)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents)
|
||||
@Override @Deprecated public void addExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents)
|
||||
{
|
||||
set(nodeRef, readers, writers);
|
||||
}
|
||||
@@ -754,9 +642,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeAllExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void removeAllExtendedSecurity(NodeRef nodeRef)
|
||||
@Override @Deprecated public void removeAllExtendedSecurity(NodeRef nodeRef)
|
||||
{
|
||||
remove(nodeRef);
|
||||
}
|
||||
@@ -764,9 +650,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers)
|
||||
@Override @Deprecated public void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers)
|
||||
{
|
||||
remove(nodeRef);
|
||||
}
|
||||
@@ -774,9 +658,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, java.util.Set, java.util.Set, boolean)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String> writers, boolean applyToParents)
|
||||
@Override @Deprecated public void removeExtendedSecurity(NodeRef nodeRef, Set<String> readers, Set<String>writers, boolean applyToParents)
|
||||
{
|
||||
remove(nodeRef);
|
||||
}
|
||||
@@ -784,9 +666,7 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
|
||||
/**
|
||||
* @see org.alfresco.module.org_alfresco_module_rm.security.DeprecatedExtendedSecurityService#removeAllExtendedSecurity(org.alfresco.service.cmr.repository.NodeRef, boolean)
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents)
|
||||
@Override @Deprecated public void removeAllExtendedSecurity(NodeRef nodeRef, boolean applyToParents)
|
||||
{
|
||||
remove(nodeRef);
|
||||
}
|
||||
|
||||
@@ -29,23 +29,14 @@ package org.alfresco.module.org_alfresco_module_rm.test.legacy.service;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.springframework.dao.ConcurrencyFailureException;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseRMTestCase;
|
||||
import org.alfresco.query.PagingRequest;
|
||||
import org.alfresco.query.PagingResults;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
|
||||
import org.alfresco.repo.site.SiteModel;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.security.AccessPermission;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.AuthorityType;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.cmr.site.SiteVisibility;
|
||||
import org.alfresco.util.GUID;
|
||||
@@ -82,7 +73,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
|
||||
private String createTestUser()
|
||||
{
|
||||
return doTestInTransaction(new Test<String>() {
|
||||
return doTestInTransaction(new Test<String>()
|
||||
{
|
||||
public String run()
|
||||
{
|
||||
String userName = GUID.generate();
|
||||
@@ -98,7 +90,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
final String elephant = createTestUser();
|
||||
final String snake = createTestUser();
|
||||
|
||||
doTestInTransaction(new Test<Void>() {
|
||||
doTestInTransaction(new Test<Void>()
|
||||
{
|
||||
public Void run()
|
||||
{
|
||||
assertFalse(extendedSecurityService.hasExtendedSecurity(filePlan));
|
||||
@@ -140,7 +133,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
final String monkey = createTestUser();
|
||||
final String elephant = createTestUser();
|
||||
|
||||
doTestInTransaction(new Test<Void>() {
|
||||
doTestInTransaction(new Test<Void>()
|
||||
{
|
||||
Set<String> extendedReaders = new HashSet<>(2);
|
||||
|
||||
public Void run() throws Exception
|
||||
@@ -195,7 +189,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
final String userWrite = createTestUser();
|
||||
final String siteShortName = GUID.generate();
|
||||
|
||||
doTestInTransaction(new Test<Void>() {
|
||||
doTestInTransaction(new Test<Void>()
|
||||
{
|
||||
public Void run() throws Exception
|
||||
{
|
||||
siteService.createSite(null, siteShortName, "test", "test", SiteVisibility.PRIVATE);
|
||||
@@ -203,7 +198,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
}
|
||||
});
|
||||
|
||||
final NodeRef documentLibrary = doTestInTransaction(new Test<NodeRef>() {
|
||||
final NodeRef documentLibrary = doTestInTransaction(new Test<NodeRef>()
|
||||
{
|
||||
public NodeRef run() throws Exception
|
||||
{
|
||||
siteService.setMembership(siteShortName, userRead, SiteModel.SITE_CONSUMER);
|
||||
@@ -212,20 +208,22 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
}
|
||||
});
|
||||
|
||||
final NodeRef record = doTestInTransaction(new Test<NodeRef>() {
|
||||
final NodeRef record = doTestInTransaction(new Test<NodeRef>()
|
||||
{
|
||||
public NodeRef run() throws Exception
|
||||
{
|
||||
NodeRef record = fileFolderService.create(documentLibrary, GUID.generate(), ContentModel.TYPE_CONTENT)
|
||||
.getNodeRef();
|
||||
NodeRef record = fileFolderService.create(documentLibrary, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef();
|
||||
recordService.createRecord(filePlan, record);
|
||||
return record;
|
||||
}
|
||||
});
|
||||
|
||||
doTestInTransaction(new Test<Void>() {
|
||||
doTestInTransaction(new Test<Void>()
|
||||
{
|
||||
public Void run() throws Exception
|
||||
{
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>() {
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// check permissions
|
||||
@@ -235,7 +233,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
}
|
||||
}, userNone);
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>() {
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// check permissions
|
||||
@@ -245,7 +244,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
}
|
||||
}, userRead);
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>() {
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// check permissions
|
||||
@@ -255,7 +255,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
}
|
||||
}, userWrite);
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>() {
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// check permissions
|
||||
@@ -265,7 +266,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
}
|
||||
}, userNone);
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>() {
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// check permissions
|
||||
@@ -275,7 +277,8 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
}
|
||||
}, userRead);
|
||||
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>() {
|
||||
AuthenticationUtil.runAs(new RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// check permissions
|
||||
@@ -289,238 +292,4 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void testConcurrentSetWithRetry()
|
||||
{
|
||||
Set<String> extendedReaders = new HashSet<>(2);
|
||||
Set<String> extendedWriters = new HashSet<>(2);
|
||||
|
||||
Set<NodeRef> documents = setupConcurrentTestCase(10, extendedReaders, extendedWriters);
|
||||
|
||||
// For each record created previously, spawn a thread to set extended security so we cause concurrency
|
||||
// failure trying to create IPR groups with the same name
|
||||
fireParallelExecutionOfSetExtendedSecurity(documents, extendedReaders, extendedWriters, true);
|
||||
|
||||
// Look for duplicated IPR groups and verify all documents have the same groups assigned
|
||||
verifyCreatedGroups(documents, false);
|
||||
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
}
|
||||
|
||||
public void testConcurrentSetWithoutRetry()
|
||||
{
|
||||
Set<String> extendedReaders = new HashSet<>(2);
|
||||
Set<String> extendedWriters = new HashSet<>(2);
|
||||
|
||||
Set<NodeRef> documents = setupConcurrentTestCase(10, extendedReaders, extendedWriters);
|
||||
|
||||
// For each record created previously, spawn a thread to set extended security so we cause concurrency
|
||||
// failure trying to create IPR groups with the same name.
|
||||
// Since there is no retry, we expect to get a ConcurrencyFailureException
|
||||
Assert.assertThrows(ConcurrencyFailureException.class, () -> {
|
||||
fireParallelExecutionOfSetExtendedSecurity(documents, extendedReaders, extendedWriters, false);
|
||||
});
|
||||
|
||||
// Look for duplicated IPR groups and verify all documents have the same groups assigned
|
||||
// Since there was a ConcurrencyFailureException some threads failed to set extended security so some
|
||||
// documents may not have IPR groups created.
|
||||
verifyCreatedGroups(documents, true);
|
||||
|
||||
AuthenticationUtil.clearCurrentSecurityContext();
|
||||
}
|
||||
|
||||
private Set<NodeRef> setupConcurrentTestCase(int concurrentThreads, Set<String> extendedReaders, Set<String> extendedWriters)
|
||||
{
|
||||
final String usera = createTestUser();
|
||||
final String userb = createTestUser();
|
||||
final String owner = createTestUser();
|
||||
|
||||
extendedReaders.add(usera);
|
||||
extendedReaders.add(userb);
|
||||
extendedWriters.add(usera);
|
||||
extendedWriters.add(userb);
|
||||
|
||||
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
|
||||
|
||||
// Create a site
|
||||
NodeRef documentLib = createSite(new HashSet<>(), new HashSet<>());
|
||||
|
||||
// Create records in the site document library
|
||||
return createRecords(concurrentThreads, documentLib, owner);
|
||||
}
|
||||
|
||||
private NodeRef createSite(Set<String> readers, Set<String> writers)
|
||||
{
|
||||
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<NodeRef>() {
|
||||
@Override
|
||||
public NodeRef execute() throws Throwable
|
||||
{
|
||||
final String siteShortName = GUID.generate();
|
||||
siteService.createSite(null, siteShortName, "test", "test", SiteVisibility.PRIVATE);
|
||||
readers.forEach(reader -> siteService.setMembership(siteShortName, reader, SiteModel.SITE_CONSUMER));
|
||||
writers.forEach(writer -> siteService.setMembership(siteShortName, writer, SiteModel.SITE_COLLABORATOR));
|
||||
return siteService.createContainer(siteShortName, SiteService.DOCUMENT_LIBRARY, null, null);
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
private Set<NodeRef> createRecords(int numRecords, NodeRef parent, String owner)
|
||||
{
|
||||
return retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Set<NodeRef>>() {
|
||||
@Override
|
||||
public Set<NodeRef> execute() throws Throwable
|
||||
{
|
||||
int createdRecords = 0;
|
||||
Set<NodeRef> documents = new HashSet<>();
|
||||
while (createdRecords < numRecords)
|
||||
{
|
||||
final NodeRef doc = fileFolderService.create(parent, GUID.generate(), ContentModel.TYPE_CONTENT).getNodeRef();
|
||||
ownableService.setOwner(doc, owner);
|
||||
recordService.createRecord(filePlan, doc, rmFolder, true);
|
||||
recordService.file(doc);
|
||||
recordService.complete(doc);
|
||||
documents.add(doc);
|
||||
createdRecords++;
|
||||
}
|
||||
return documents;
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
private void setExtendedSecurity(NodeRef doc, Set<String> readers, Set<String> writers, boolean useRetry)
|
||||
{
|
||||
if (!useRetry)
|
||||
{
|
||||
setExtendedSecurity(doc, readers, writers);
|
||||
return;
|
||||
}
|
||||
|
||||
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
setExtendedSecurity(doc, readers, writers);
|
||||
return null;
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
private void setExtendedSecurity(NodeRef doc, Set<String> readers, Set<String> writers)
|
||||
{
|
||||
AuthenticationUtil.setAdminUserAsFullyAuthenticatedUser();
|
||||
extendedSecurityService.set(doc, readers, writers);
|
||||
}
|
||||
|
||||
private void fireParallelExecutionOfSetExtendedSecurity(Set<NodeRef> documents, Set<String> extendedReaders, Set<String> extendedWriters, boolean useRetry)
|
||||
{
|
||||
CompletableFuture<?>[] futures = documents.stream()
|
||||
.map(doc -> CompletableFuture.runAsync(() -> setExtendedSecurity(doc, extendedReaders, extendedWriters, useRetry)))
|
||||
.toArray(CompletableFuture[]::new);
|
||||
|
||||
try
|
||||
{
|
||||
CompletableFuture.allOf(futures).join();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof ConcurrencyFailureException)
|
||||
{
|
||||
throw (ConcurrencyFailureException) cause;
|
||||
}
|
||||
throw new RuntimeException("Error during parallel execution", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyCreatedGroups(Set<NodeRef> documents, boolean onlyDuplicatesValidation)
|
||||
{
|
||||
retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
Set<String> expectedAuthorities = null;
|
||||
Set<Set<String>> errors = new HashSet<>();
|
||||
for (NodeRef doc : documents)
|
||||
{
|
||||
Set<AccessPermission> permissions = permissionService.getAllSetPermissions(doc);
|
||||
Set<String> authorities = getDocumentAuthorities(permissions);
|
||||
Set<String> authoritiesById = getAuthorityIds(authorities);
|
||||
|
||||
verifyIPRGroups(authorities, onlyDuplicatesValidation);
|
||||
|
||||
if (onlyDuplicatesValidation)
|
||||
{
|
||||
// Some documents may not have IPR groups created if there was a ConcurrencyFailureException
|
||||
continue;
|
||||
}
|
||||
|
||||
// All documents should have the same exact set of groups assigned
|
||||
if (expectedAuthorities == null)
|
||||
{
|
||||
expectedAuthorities = authoritiesById;
|
||||
}
|
||||
|
||||
if (!expectedAuthorities.equals(authoritiesById))
|
||||
{
|
||||
errors.add(authoritiesById);
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue("Unexpected authorities linked to document", errors.isEmpty());
|
||||
|
||||
return null;
|
||||
}
|
||||
}, false, true);
|
||||
}
|
||||
|
||||
private Set<String> getDocumentAuthorities(Set<AccessPermission> permissions)
|
||||
{
|
||||
Set<String> authorities = new HashSet<>();
|
||||
|
||||
for (AccessPermission accessPermission : permissions)
|
||||
{
|
||||
String authority = accessPermission.getAuthority();
|
||||
String authName = authorityService.getName(AuthorityType.GROUP, authority);
|
||||
authorities.add(authName);
|
||||
|
||||
}
|
||||
return authorities;
|
||||
}
|
||||
|
||||
private Set<String> getAuthorityIds(Set<String> authorities)
|
||||
{
|
||||
Set<String> authorityIds = new HashSet<>();
|
||||
for (String authority : authorities)
|
||||
{
|
||||
String authId = authorityService.getAuthorityNodeRef(authority) != null
|
||||
? authorityService.getAuthorityNodeRef(authority).getId()
|
||||
: null;
|
||||
authorityIds.add(authId);
|
||||
}
|
||||
return authorityIds;
|
||||
}
|
||||
|
||||
private void verifyIPRGroups(Set<String> authorities, boolean onlyDuplicatesValidation)
|
||||
{
|
||||
boolean hasGroupIPR = false;
|
||||
|
||||
for (String authorityName : authorities)
|
||||
{
|
||||
String shortName = authorityService.getShortName(authorityName);
|
||||
|
||||
if (authorityName.startsWith("GROUP_IPR"))
|
||||
{
|
||||
hasGroupIPR = true;
|
||||
PagingResults<String> results = authorityService.getAuthorities(AuthorityType.GROUP, null, shortName, false,
|
||||
false, new PagingRequest(0, 10));
|
||||
|
||||
assertEquals("No duplicated IPR group expected", 1, results.getPage().size());
|
||||
}
|
||||
}
|
||||
|
||||
if (!onlyDuplicatesValidation)
|
||||
{
|
||||
assertTrue("No IPR Groups created", hasGroupIPR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
# Version label
|
||||
version.major=23
|
||||
version.minor=7
|
||||
version.revision=0
|
||||
version.minor=4
|
||||
version.revision=1
|
||||
version.label=
|
||||
|
||||
# Edition label
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
/*
|
||||
* #%L
|
||||
* Alfresco Records Management Module
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* -
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
* -
|
||||
* Alfresco is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* -
|
||||
* Alfresco is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
* -
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
* #L%
|
||||
*/
|
||||
package org.alfresco.module.org_alfresco_module_rm.content.cleanser;
|
||||
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import org.alfresco.module.org_alfresco_module_rm.test.util.BaseUnitTest;
|
||||
import org.alfresco.service.cmr.repository.ContentIOException;
|
||||
|
||||
/**
|
||||
* Eager content store cleaner unit test.
|
||||
*
|
||||
*/
|
||||
public class ContentCleanserSevenPassUnitTest extends BaseUnitTest
|
||||
{
|
||||
@InjectMocks
|
||||
@Spy
|
||||
private ContentCleanserSevenPass contentCleanserSevenPass = new ContentCleanserSevenPass()
|
||||
{
|
||||
/** dummy implementations */
|
||||
@Override
|
||||
protected void overwrite(File file, OverwriteOperation overwriteOperation)
|
||||
{
|
||||
// Intentionally left empty
|
||||
}
|
||||
};
|
||||
|
||||
@Mock
|
||||
private File mockedFile;
|
||||
|
||||
/**
|
||||
* Given that a file exists When I cleanse it Then the content is overwritten
|
||||
*/
|
||||
@Test
|
||||
public void cleanseFile()
|
||||
{
|
||||
when(mockedFile.exists()).thenReturn(true);
|
||||
when(mockedFile.canWrite()).thenReturn(true);
|
||||
contentCleanserSevenPass.cleanse(mockedFile);
|
||||
verify(contentCleanserSevenPass, times(2)).overwrite(mockedFile, contentCleanserSevenPass.overwriteOnes);
|
||||
verify(contentCleanserSevenPass, times(3)).overwrite(mockedFile, contentCleanserSevenPass.overwriteZeros);
|
||||
verify(contentCleanserSevenPass, times(2)).overwrite(mockedFile, contentCleanserSevenPass.overwriteRandom);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given that the file does not exist When I cleanse it Then an exception is thrown
|
||||
*/
|
||||
@Test(expected = ContentIOException.class)
|
||||
public void fileDoesNotExist()
|
||||
{
|
||||
when(mockedFile.exists()).thenReturn(false);
|
||||
when(mockedFile.canWrite()).thenReturn(true);
|
||||
contentCleanserSevenPass.cleanse(mockedFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given that I can not write to the file When I cleanse it Then an exception is thrown
|
||||
*/
|
||||
@Test(expected = ContentIOException.class)
|
||||
public void cantWriteToFile()
|
||||
{
|
||||
when(mockedFile.exists()).thenReturn(true);
|
||||
when(mockedFile.canWrite()).thenReturn(false);
|
||||
contentCleanserSevenPass.cleanse(mockedFile);
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,6 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.RenditionModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.capability.RMPermissionModel;
|
||||
import org.alfresco.module.org_alfresco_module_rm.fileplan.FilePlanService;
|
||||
@@ -68,7 +67,6 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti
|
||||
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.repository.NodeService;
|
||||
import org.alfresco.service.cmr.repository.StoreRef;
|
||||
import org.alfresco.service.cmr.security.AccessPermission;
|
||||
import org.alfresco.service.cmr.security.AccessStatus;
|
||||
import org.alfresco.service.cmr.security.AuthorityService;
|
||||
@@ -525,104 +523,6 @@ public class ExtendedSecurityServiceImplUnitTest
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a node with no previous IPR groups assigned
|
||||
* And having pre-existing IPR groups matching the ones we need
|
||||
* When I add some read and write authorities but with a different casing
|
||||
* Then the existing IPR groups are used
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test public void addExtendedSecurityWithMixedCasingUsernames()
|
||||
{
|
||||
// Have the usernames in the node as the correct usernames but with incorrect casing
|
||||
String user1 = "UseR";
|
||||
String user2 = "UseR_w";
|
||||
|
||||
// Incorrect IPR Group names
|
||||
Set<String> diffCasingReaders = Stream.of(user1, GROUP).collect(Collectors.toSet());
|
||||
Set<String> diffCasingWriters = Stream.of(user2, GROUP_W).collect(Collectors.toSet());
|
||||
String wrongReadGroupPrefix = extendedSecurityService.getIPRGroupPrefixShortName(READER_GROUP_PREFIX, diffCasingReaders);
|
||||
String wrongWriteGroupPrefix = extendedSecurityService.getIPRGroupPrefixShortName(WRITER_GROUP_PREFIX, diffCasingWriters);
|
||||
String wrongReadGroup = wrongReadGroupPrefix + "0";
|
||||
String wrongWriteGroup = wrongWriteGroupPrefix + "0";
|
||||
|
||||
// Correct Group names
|
||||
String correctReadGroup = readGroupPrefix + "0";
|
||||
String correctWriteGroup = writeGroupPrefix + "0";
|
||||
|
||||
// If queried for the correct groups, return the results
|
||||
PagingResults<String> mockedCorrectReadPResults = mock(PagingResults.class);
|
||||
PagingResults<String> mockedCorrectWritePResults = mock(PagingResults.class);
|
||||
when(mockedCorrectReadPResults.getPage())
|
||||
.thenReturn(Stream.of(GROUP_PREFIX + correctReadGroup).collect(Collectors.toList()));
|
||||
when(mockedAuthorityService.getAuthorities(
|
||||
eq(AuthorityType.GROUP),
|
||||
eq(RMAuthority.ZONE_APP_RM),
|
||||
eq(readGroupPrefix),
|
||||
eq(false),
|
||||
eq(false),
|
||||
any(PagingRequest.class)))
|
||||
.thenReturn(mockedCorrectReadPResults);
|
||||
|
||||
when(mockedCorrectWritePResults.getPage())
|
||||
.thenReturn(Stream.of(GROUP_PREFIX + correctWriteGroup).collect(Collectors.toList()));
|
||||
when(mockedAuthorityService.getAuthorities(
|
||||
eq(AuthorityType.GROUP),
|
||||
eq(RMAuthority.ZONE_APP_RM),
|
||||
eq(writeGroupPrefix),
|
||||
eq(false),
|
||||
eq(false),
|
||||
any(PagingRequest.class)))
|
||||
.thenReturn(mockedCorrectWritePResults);
|
||||
|
||||
// Don't return results for the incorrect groups (lenient as these may not be called with normalization enabled)
|
||||
PagingResults<String> mockedWrongReadPResults = mock(PagingResults.class);
|
||||
PagingResults<String> mockedWrongWritePResults = mock(PagingResults.class);
|
||||
lenient().when(mockedWrongReadPResults.getPage())
|
||||
.thenReturn(Collections.emptyList());
|
||||
lenient().when(mockedAuthorityService.getAuthorities(
|
||||
eq(AuthorityType.GROUP),
|
||||
eq(RMAuthority.ZONE_APP_RM),
|
||||
eq(wrongReadGroupPrefix),
|
||||
eq(false),
|
||||
eq(false),
|
||||
any(PagingRequest.class)))
|
||||
.thenReturn(mockedWrongReadPResults);
|
||||
|
||||
lenient().when(mockedWrongWritePResults.getPage())
|
||||
.thenReturn(Collections.emptyList());
|
||||
lenient().when(mockedAuthorityService.getAuthorities(
|
||||
eq(AuthorityType.GROUP),
|
||||
eq(RMAuthority.ZONE_APP_RM),
|
||||
eq(wrongWriteGroupPrefix),
|
||||
eq(false),
|
||||
eq(false),
|
||||
any(PagingRequest.class)))
|
||||
.thenReturn(mockedWrongWritePResults);
|
||||
|
||||
// The users do exist, despite being in a different casing and are able to be retrieved
|
||||
NodeRef noderefUser1 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, USER);
|
||||
when(mockedAuthorityService.authorityExists(user1)).thenReturn(true);
|
||||
when(mockedAuthorityService.getAuthorityNodeRef(user1)).thenReturn(noderefUser1);
|
||||
when(mockedNodeService.getProperty(noderefUser1, ContentModel.PROP_USERNAME)).thenReturn(USER);
|
||||
|
||||
NodeRef noderefUser2 = new NodeRef(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE, USER_W);
|
||||
when(mockedAuthorityService.authorityExists(user2)).thenReturn(true);
|
||||
when(mockedAuthorityService.getAuthorityNodeRef(user2)).thenReturn(noderefUser2);
|
||||
when(mockedNodeService.getProperty(noderefUser2, ContentModel.PROP_USERNAME)).thenReturn(USER_W);
|
||||
|
||||
// Set the extended security service to normalize usernames
|
||||
extendedSecurityService.setEnableUsernameNormalization(true);
|
||||
extendedSecurityService.set(nodeRef, diffCasingReaders, diffCasingWriters);
|
||||
|
||||
// Verify that the incorrect read group is not created
|
||||
verify(mockedAuthorityService, never()).createAuthority(AuthorityType.GROUP, wrongReadGroup, wrongReadGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
|
||||
|
||||
// Verify that the incorrect write group is not created
|
||||
verify(mockedAuthorityService, never()).createAuthority(AuthorityType.GROUP, wrongWriteGroup, wrongWriteGroup, Collections.singleton(RMAuthority.ZONE_APP_RM));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a node with no previous IPR groups assigned
|
||||
* And existing IPR groups matches existing has, but not exact match
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
@@ -51,8 +51,8 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
import org.alfresco.service.cmr.site.SiteInfo;
|
||||
import org.alfresco.service.cmr.wiki.WikiPageInfo;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.springframework.extensions.webscripts.Cache;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
@@ -92,7 +92,7 @@ public class WikiPageGet extends AbstractWikiWebScript
|
||||
{
|
||||
links.add(link);
|
||||
// build the list of available pages
|
||||
WikiPageInfo wikiPage = wikiService.getWikiPage(site.getShortName(), StringEscapeUtils.unescapeHtml4(link));
|
||||
WikiPageInfo wikiPage = wikiService.getWikiPage(site.getShortName(), StringEscapeUtils.unescapeHtml(link));
|
||||
if (wikiPage != null)
|
||||
{
|
||||
pageTitles.add(wikiPage.getTitle());
|
||||
|
||||
@@ -91,15 +91,6 @@ function doclist_getAllNodes(parsedArgs, filterParams, query, totalItemCount)
|
||||
};
|
||||
}
|
||||
|
||||
function sanitizeJunkFavouriteKeys(favourites){
|
||||
for (var key in favourites) {
|
||||
if (!key || key.trim() === "") {
|
||||
delete favourites[key];
|
||||
}
|
||||
}
|
||||
return favourites;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point: Create collection of documents and folders in the given space
|
||||
*
|
||||
@@ -133,28 +124,6 @@ function doclist_main()
|
||||
if (logger.isLoggingEnabled())
|
||||
logger.log("doclist.lib.js - NodeRef: " + parsedArgs.nodeRef + " Query: " + query);
|
||||
|
||||
favourites = sanitizeJunkFavouriteKeys(favourites);
|
||||
|
||||
if(Object.keys(favourites).length === 0 && query === null)
|
||||
{
|
||||
return {
|
||||
luceneQuery: "",
|
||||
paging: {
|
||||
totalRecords: 0,
|
||||
startIndex: 0
|
||||
},
|
||||
container: parsedArgs.rootNode,
|
||||
parent: null,
|
||||
onlineEditing: utils.moduleInstalled("org.alfresco.module.vti"),
|
||||
itemCount: {
|
||||
folders: 0,
|
||||
documents: 0
|
||||
},
|
||||
items: [],
|
||||
customJSON: slingshotDocLib.getJSON()
|
||||
};
|
||||
}
|
||||
|
||||
var totalItemCount = filterParams.limitResults ? parseInt(filterParams.limitResults, 10) : -1;
|
||||
// For all sites documentLibrary query we pull in all available results and post filter
|
||||
if (totalItemCount === 0) totalItemCount = -1;
|
||||
|
||||
@@ -181,8 +181,6 @@ var Filters =
|
||||
|
||||
case "favourites":
|
||||
for (var favourite in favourites)
|
||||
{
|
||||
if (favourite && favourite.trim() !== "")
|
||||
{
|
||||
if (filterQuery)
|
||||
{
|
||||
@@ -190,7 +188,6 @@ var Filters =
|
||||
}
|
||||
filterQuery += "ID:\"" + favourite + "\"";
|
||||
}
|
||||
}
|
||||
|
||||
if (filterQuery.length !== 0)
|
||||
{
|
||||
@@ -204,13 +201,7 @@ var Filters =
|
||||
else
|
||||
{
|
||||
// empty favourites query
|
||||
logger.warn("No favourites found for user: " + person.properties.userName);
|
||||
return {
|
||||
query: null,
|
||||
limitResults: 0,
|
||||
sort: [],
|
||||
language: "lucene"
|
||||
};
|
||||
filterQuery = "+ID:\"\"";
|
||||
}
|
||||
|
||||
filterParams.query = filterQuery;
|
||||
|
||||
@@ -80,11 +80,6 @@ function runAction(p_params)
|
||||
{
|
||||
result.fileExist = true;
|
||||
}
|
||||
if (error.indexOf("FolderExistsException") != -1)
|
||||
{
|
||||
result.fileExist = true;
|
||||
result.type = "folder";
|
||||
}
|
||||
}
|
||||
|
||||
results.push(result);
|
||||
|
||||
@@ -45,7 +45,7 @@ import org.alfresco.service.cmr.wiki.WikiPageInfo;
|
||||
import org.alfresco.service.cmr.wiki.WikiService;
|
||||
import org.alfresco.service.transaction.TransactionService;
|
||||
import org.alfresco.util.PropertyMap;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.apache.commons.lang.StringEscapeUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.json.JSONArray;
|
||||
@@ -996,7 +996,7 @@ public class WikiRestApiTest extends BaseWebScriptTest
|
||||
String link = m.group(1);
|
||||
link += "?title=<script>alert('xss');</script>";
|
||||
WikiPageInfo wikiPage2 = this.wikiService.getWikiPage(SITE_SHORT_NAME_WIKI, link);
|
||||
WikiPageInfo wikiPage1 = this.wikiService.getWikiPage(SITE_SHORT_NAME_WIKI, StringEscapeUtils.unescapeHtml4(link));
|
||||
WikiPageInfo wikiPage1 = this.wikiService.getWikiPage(SITE_SHORT_NAME_WIKI, StringEscapeUtils.unescapeHtml(link));
|
||||
assertEquals(wikiPage2, wikiPage1);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -9,6 +9,6 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
</project>
|
||||
|
||||
@@ -37,6 +37,7 @@ commons-fileupload http://jakarta.apache.org/commons/
|
||||
commons-httpclient http://jakarta.apache.org/commons/
|
||||
commons-io http://jakarta.apache.org/commons/
|
||||
commons-jxpath http://jakarta.apache.org/commons/
|
||||
commons-lang http://jakarta.apache.org/commons/
|
||||
commons-lang3 http://jakarta.apache.org/commons/
|
||||
commons-logging http://jakarta.apache.org/commons/
|
||||
commons-net http://jakarta.apache.org/commons/
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
SOLR6_TAG=2.0.17
|
||||
SOLR6_TAG=2.0.13
|
||||
POSTGRES_TAG=15.4
|
||||
ACTIVEMQ_TAG=5.18.3-jre17-rockylinux8
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
## Synopsis
|
||||
|
||||
**TAS**( **T**est **A**utomation **S**ystem)- **CMIS** is the project that handles the automated tests related only to CMIS API integrated with Alfresco One [Alfresco CMIS API](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/Reference/CMIS-API).
|
||||
**TAS**( **T**est **A**utomation **S**ystem)- **CMIS** is the project that handles the automated tests related only to CMIS API integrated with Alfresco One [Alfresco CMIS API](http://docs.alfresco.com/5.1/pra/1/topics/cmis-welcome.html).
|
||||
|
||||
It is based on Apache Maven, compatible with major IDEs and is using also Spring capabilities for dependency injection.
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<organization>
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.alfresco.utility.testrail.annotation.TestRail;
|
||||
import org.apache.chemistry.opencmis.commons.exceptions.CmisObjectNotFoundException;
|
||||
import org.apache.chemistry.opencmis.commons.exceptions.CmisPermissionDeniedException;
|
||||
import org.apache.chemistry.opencmis.commons.exceptions.CmisUnauthorizedException;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
||||
@@ -27,7 +27,7 @@ Back to [TAS Master Documentation](https://git.alfresco.com/tas/alfresco-tas-uti
|
||||
|
||||
## Synopsis
|
||||
|
||||
**TAS**( **T**est **A**utomation **S**ystem)- **RESTAPI** is the project that handles the automated tests related only to [Alfresco REST API](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/REST-API-Guide).
|
||||
**TAS**( **T**est **A**utomation **S**ystem)- **RESTAPI** is the project that handles the automated tests related only to [Alfresco REST API](http://docs.alfresco.com/5.1/pra/1/topics/pra-welcome.html).
|
||||
|
||||
It is based on Apache Maven, compatible with major IDEs and is using also Spring capabilities for dependency injection.
|
||||
|
||||
@@ -271,7 +271,7 @@ restClient.onResponse().assertThat().body("entry.modifiedBy.firstName", org.hamc
|
||||
|
||||
### How to generate models or check coverage
|
||||
|
||||
There are some simple generators that could parse [Swagger YAML](https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Develop/REST-API-Guide/Things-to-Know-Before-You-Start/The-API-Explorer-is-Your-Source-of-Truth) files and provide some usefull information to you like:
|
||||
There are some simple generators that could parse [Swagger YAML](http://docs.alfresco.com/community/concepts/alfresco-sdk-tutorials-using-rest-api-explorer.html) files and provide some usefull information to you like:
|
||||
|
||||
a) Show on screen the actual coverage of TAS vs requests that exists in each YAML file - defined in pom.xml)
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
@@ -17,7 +17,7 @@
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<rest.api.explorer.branch>master</rest.api.explorer.branch>
|
||||
<httpclient-osgi-version>4.5.6</httpclient-osgi-version>
|
||||
<commons-lang3.version>3.18.0</commons-lang3.version>
|
||||
<commons-lang3.version>3.17.0</commons-lang3.version>
|
||||
<scribejava-apis.version>8.3.3</scribejava-apis.version>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -26,13 +26,6 @@
|
||||
package org.alfresco.rest.rules;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
|
||||
import static org.springframework.http.HttpStatus.NOT_FOUND;
|
||||
|
||||
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.ERROR_MESSAGE_ACCESS_RESTRICTED;
|
||||
import static org.alfresco.rest.actions.access.AccessRestrictionUtil.MAIL_ACTION;
|
||||
import static org.alfresco.rest.rules.RulesTestsUtils.CHECKIN_ACTION;
|
||||
@@ -52,6 +45,11 @@ import static org.alfresco.utility.model.FileModel.getRandomFileModel;
|
||||
import static org.alfresco.utility.model.FileType.TEXT_PLAIN;
|
||||
import static org.alfresco.utility.model.UserModel.getRandomUserModel;
|
||||
import static org.alfresco.utility.report.log.Step.STEP;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.http.HttpStatus.BAD_REQUEST;
|
||||
import static org.springframework.http.HttpStatus.CREATED;
|
||||
import static org.springframework.http.HttpStatus.FORBIDDEN;
|
||||
import static org.springframework.http.HttpStatus.NOT_FOUND;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
@@ -63,13 +61,10 @@ import java.util.stream.IntStream;
|
||||
import jakarta.json.Json;
|
||||
import jakarta.json.JsonObject;
|
||||
|
||||
import org.apache.chemistry.opencmis.client.api.CmisObject;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import org.alfresco.rest.model.RestActionBodyExecTemplateModel;
|
||||
import org.alfresco.rest.model.RestActionConstraintModel;
|
||||
import org.alfresco.rest.model.RestCompositeConditionDefinitionModel;
|
||||
import org.alfresco.rest.model.RestPaginationModel;
|
||||
import org.alfresco.rest.model.RestRuleModel;
|
||||
import org.alfresco.rest.model.RestRuleModelsCollection;
|
||||
import org.alfresco.utility.constants.UserRole;
|
||||
@@ -79,6 +74,9 @@ import org.alfresco.utility.model.FolderModel;
|
||||
import org.alfresco.utility.model.SiteModel;
|
||||
import org.alfresco.utility.model.TestGroup;
|
||||
import org.alfresco.utility.model.UserModel;
|
||||
import org.apache.chemistry.opencmis.client.api.CmisObject;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests for POST /nodes/{nodeId}/rule-sets/{ruleSetId}/rules.
|
||||
@@ -103,7 +101,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
* <p>
|
||||
* Also check that the isShared field is not returned when not requested.
|
||||
*/
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
|
||||
public void createRule()
|
||||
{
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModelWithModifiedValues();
|
||||
@@ -119,7 +117,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check creating a rule in a non-existent folder returns an error. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRuleInNonExistentFolder()
|
||||
{
|
||||
STEP("Try to create a rule in non-existent folder.");
|
||||
@@ -136,7 +134,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check creating a rule in a non-existent rule set returns an error. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRuleInNonExistentRuleSet()
|
||||
{
|
||||
STEP("Try to create a rule in non-existent rule set.");
|
||||
@@ -150,7 +148,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Try to create a rule without a name and check the error. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRuleWithEmptyName()
|
||||
{
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModel("");
|
||||
@@ -162,7 +160,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check we can create two rules with the same name. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void duplicateRuleNameIsAcceptable()
|
||||
{
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModel("duplicateRuleName");
|
||||
@@ -177,7 +175,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check that a user without permission to view the folder cannot create a rule in it. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void requireReadPermissionToCreateRule()
|
||||
{
|
||||
STEP("Create a user and use them to create a private site containing a folder");
|
||||
@@ -196,7 +194,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check that a Collaborator cannot create a rule in a folder in a private site. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void siteCollaboratorCannotCreateRule()
|
||||
{
|
||||
testRolePermissionsWith(SiteCollaborator);
|
||||
@@ -206,7 +204,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check that a Contributor cannot create a rule in a private folder. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void siteContributorCannotCreateRule()
|
||||
{
|
||||
testRolePermissionsWith(SiteContributor);
|
||||
@@ -216,7 +214,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check that a Consumer cannot create a rule in a folder in a private site. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void siteConsumerCannotCreateRule()
|
||||
{
|
||||
testRolePermissionsWith(SiteConsumer);
|
||||
@@ -226,7 +224,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check that a siteManager can create a rule in a folder in a private site. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void siteManagerCanCreateRule()
|
||||
{
|
||||
testRolePermissionsWith(SiteManager)
|
||||
@@ -236,7 +234,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check we can't create a rule under a document node. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void tryToCreateRuleUnderDocument()
|
||||
{
|
||||
STEP("Create a document.");
|
||||
@@ -252,7 +250,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check we can create several rules. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRules()
|
||||
{
|
||||
STEP("Create a list of rules in one POST request");
|
||||
@@ -265,13 +263,14 @@ public class CreateRulesTests extends RulesRestTest
|
||||
restClient.assertStatusCodeIs(CREATED);
|
||||
|
||||
assertEquals("Unexpected number of rules received in response.", ruleNames.size(), rules.getEntries().size());
|
||||
IntStream.range(0, ruleModels.size()).forEach(i -> rules.getEntries().get(i).onModel()
|
||||
IntStream.range(0, ruleModels.size()).forEach(i ->
|
||||
rules.getEntries().get(i).onModel()
|
||||
.assertThat().field("id").isNotNull()
|
||||
.assertThat().field("name").is(ruleNames.get(i)));
|
||||
}
|
||||
|
||||
/** Check we can create over 100 rules and get them all back in response. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createOver100Rules()
|
||||
{
|
||||
STEP("Create a list of 120 rules in one POST request");
|
||||
@@ -288,7 +287,8 @@ public class CreateRulesTests extends RulesRestTest
|
||||
restClient.assertStatusCodeIs(CREATED);
|
||||
|
||||
assertEquals("Unexpected number of rules received in response.", ruleCount, rules.getEntries().size());
|
||||
IntStream.range(0, ruleModels.size()).forEach(i -> rules.getEntries().get(i).onModel()
|
||||
IntStream.range(0, ruleModels.size()).forEach(i ->
|
||||
rules.getEntries().get(i).onModel()
|
||||
.assertThat().field("id").isNotNull()
|
||||
.assertThat().field("name").is(ruleNamePrefix + (i + 1)));
|
||||
|
||||
@@ -302,7 +302,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Try to create several rules with an error in one of them. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRulesWithOneError()
|
||||
{
|
||||
STEP("Try to create a three rules but the middle one has an error.");
|
||||
@@ -319,7 +319,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check we can create a rule without description. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRuleWithoutDescription()
|
||||
{
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
@@ -335,7 +335,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check we can create a rule without specifying triggers but with the default "inbound" value. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRuleWithoutTriggers()
|
||||
{
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
@@ -351,7 +351,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check we can create a rule without error script. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRuleWithoutErrorScript()
|
||||
{
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
@@ -367,7 +367,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check we can create a rule with irrelevant isShared flag, and it doesn't have impact to the process. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRuleWithSharedFlag()
|
||||
{
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
@@ -384,7 +384,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check we can create a rule. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES, TestGroup.SANITY })
|
||||
public void createRuleAndIncludeFieldsInResponse()
|
||||
{
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModel("ruleName");
|
||||
@@ -412,7 +412,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check that the folder's owner can create rules, even if it is in a private site they aren't a member of. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void checkOwnerCanCreateRule()
|
||||
{
|
||||
STEP("Use admin to create a private site.");
|
||||
@@ -431,7 +431,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check that an administrator can create a rule in a private site even if they aren't a member. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void checkAdminCanCreateRule()
|
||||
{
|
||||
STEP("Use a user to create a private site with a folder.");
|
||||
@@ -446,7 +446,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check that a coordinator can create rules in folders outside sites. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void checkCoordinatorCanCreateRule()
|
||||
{
|
||||
STEP("Create a folder in the user's file space.");
|
||||
@@ -454,7 +454,11 @@ public class CreateRulesTests extends RulesRestTest
|
||||
|
||||
STEP("Create another user as a coordinator for this folder.");
|
||||
UserModel coordinator = dataUser.createRandomTestUser("Rules");
|
||||
/* Update folder node properties to add a coordinator { "permissions": { "isInheritanceEnabled": true, "locallySet": { "authorityId": "coordinator.getUsername()", "name": "Coordinator", "accessStatus":"ALLOWED" } } } */
|
||||
/*
|
||||
Update folder node properties to add a coordinator
|
||||
{ "permissions": { "isInheritanceEnabled": true, "locallySet": { "authorityId": "coordinator.getUsername()",
|
||||
"name": "Coordinator", "accessStatus":"ALLOWED" } } }
|
||||
*/
|
||||
String putBody = getAddPermissionsBody(coordinator.getUsername(), "Coordinator");
|
||||
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).updateNode(putBody);
|
||||
|
||||
@@ -466,7 +470,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check that an editor cannot create rules in folders outside sites. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void checkEditorCannotCreateRule()
|
||||
{
|
||||
STEP("Create a folder in the user's file space.");
|
||||
@@ -474,7 +478,11 @@ public class CreateRulesTests extends RulesRestTest
|
||||
|
||||
STEP("Create another user as a editor for this folder.");
|
||||
UserModel editor = dataUser.createRandomTestUser();
|
||||
/* Update folder node properties to add an editor { "permissions": { "isInheritanceEnabled": true, "locallySet": { "authorityId": "editor.getUsername()", "name": "Coordinator", "accessStatus":"ALLOWED" } } } */
|
||||
/*
|
||||
Update folder node properties to add an editor
|
||||
{ "permissions": { "isInheritanceEnabled": true, "locallySet": { "authorityId": "editor.getUsername()",
|
||||
"name": "Coordinator", "accessStatus":"ALLOWED" } } }
|
||||
*/
|
||||
String putBody = getAddPermissionsBody(editor.getUsername(), "Editor");
|
||||
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).updateNode(putBody);
|
||||
|
||||
@@ -486,7 +494,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
}
|
||||
|
||||
/** Check that a collaborator cannot create rules in folders outside sites. */
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void checkCollaboratorCannotCreateRule()
|
||||
{
|
||||
STEP("Create a folder in the user's file space.");
|
||||
@@ -494,7 +502,11 @@ public class CreateRulesTests extends RulesRestTest
|
||||
|
||||
STEP("Create another user as a collaborator for this folder.");
|
||||
UserModel collaborator = dataUser.createRandomTestUser();
|
||||
/* Update folder node properties to add a collaborator { "permissions": { "isInheritanceEnabled": true, "locallySet": { "authorityId": "collaborator.getUsername()", "name": "Coordinator", "accessStatus":"ALLOWED" } } } */
|
||||
/*
|
||||
Update folder node properties to add a collaborator
|
||||
{ "permissions": { "isInheritanceEnabled": true, "locallySet": { "authorityId": "collaborator.getUsername()",
|
||||
"name": "Coordinator", "accessStatus":"ALLOWED" } } }
|
||||
*/
|
||||
String putBody = getAddPermissionsBody(collaborator.getUsername(), "Collaborator");
|
||||
restClient.authenticateUser(user).withCoreAPI().usingNode(folder).updateNode(putBody);
|
||||
|
||||
@@ -644,7 +656,8 @@ public class CreateRulesTests extends RulesRestTest
|
||||
public void createRuleWithNotApplicableActionShouldFail()
|
||||
{
|
||||
final RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
final RestActionBodyExecTemplateModel invalidAction = rulesUtils.createCustomActionModel(RulesTestsUtils.DELETE_RENDITION_ACTION, Map.of("dummy-key", "dummy-value"));
|
||||
final RestActionBodyExecTemplateModel invalidAction =
|
||||
rulesUtils.createCustomActionModel(RulesTestsUtils.DELETE_RENDITION_ACTION, Map.of("dummy-key", "dummy-value"));
|
||||
ruleModel.setActions(List.of(invalidAction));
|
||||
|
||||
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet().createSingleRule(ruleModel);
|
||||
@@ -660,7 +673,8 @@ public class CreateRulesTests extends RulesRestTest
|
||||
public void createRuleWithMissingActionParametersShouldFail()
|
||||
{
|
||||
final RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
final RestActionBodyExecTemplateModel invalidAction = rulesUtils.createCustomActionModel(RulesTestsUtils.COPY_ACTION, Collections.emptyMap());
|
||||
final RestActionBodyExecTemplateModel invalidAction =
|
||||
rulesUtils.createCustomActionModel(RulesTestsUtils.COPY_ACTION, Collections.emptyMap());
|
||||
ruleModel.setActions(List.of(invalidAction));
|
||||
|
||||
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||
@@ -722,7 +736,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
public void createRuleWithoutMandatoryActionParametersShouldFail()
|
||||
{
|
||||
final RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
final RestActionBodyExecTemplateModel invalidAction = rulesUtils.createCustomActionModel(COPY_ACTION, Map.of("deep-copy", false));
|
||||
final RestActionBodyExecTemplateModel invalidAction = rulesUtils.createCustomActionModel(COPY_ACTION, Map.of("deep-copy",false));
|
||||
ruleModel.setActions(List.of(invalidAction));
|
||||
|
||||
restClient.authenticateUser(user).withPrivateAPI().usingNode(ruleFolder).usingDefaultRuleSet()
|
||||
@@ -735,7 +749,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
/**
|
||||
* Check we get error when attempting to create a rule that copies files to a non-existent folder.
|
||||
*/
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRuleThatUsesNonExistentNode()
|
||||
{
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
@@ -747,13 +761,13 @@ public class CreateRulesTests extends RulesRestTest
|
||||
.createSingleRule(ruleModel);
|
||||
|
||||
restClient.assertStatusCodeIs(NOT_FOUND);
|
||||
restClient.assertLastError().containsSummary("Destination folder having Id: non-existent-node no longer exists. Please update your rule definition.");
|
||||
restClient.assertLastError().containsSummary("The entity with id: non-existent-node was not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check we get error when attempting to create a rule that references a folder that the user does not have read permission for.
|
||||
*/
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRuleThatUsesNodeWithoutReadPermission()
|
||||
{
|
||||
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
|
||||
@@ -774,7 +788,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
/**
|
||||
* Check we get error when attempting to create a rule that copies files to a folder that a user only has read permission for.
|
||||
*/
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void createRuleThatWritesToNodeWithoutPermission()
|
||||
{
|
||||
SiteModel privateSite = dataSite.usingAdmin().createPrivateRandomSite();
|
||||
@@ -814,6 +828,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
restClient.assertLastError().containsSummary("Node is not a folder " + fileModel.getNodeRef());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check we get error when attempting to create a rule with mail action defined with non-existing mail template.
|
||||
*/
|
||||
@@ -845,7 +860,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
/**
|
||||
* Check the user can create a rule with a script.
|
||||
*/
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void checkCanUseScriptInRule()
|
||||
{
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
@@ -862,7 +877,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
/**
|
||||
* Check the script has to be stored in the scripts directory in the data dictionary.
|
||||
*/
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void checkCantUseNodeOutsideScriptsDirectory()
|
||||
{
|
||||
STEP("Copy script to location outside data dictionary.");
|
||||
@@ -892,7 +907,7 @@ public class CreateRulesTests extends RulesRestTest
|
||||
/**
|
||||
* Check a real category needs to be supplied when linking to a category.
|
||||
*/
|
||||
@Test(groups = {TestGroup.REST_API, TestGroup.RULES})
|
||||
@Test (groups = { TestGroup.REST_API, TestGroup.RULES })
|
||||
public void checkLinkToCategoryNeedsRealCategory()
|
||||
{
|
||||
STEP("Attempt to link to a category with a folder node, rather than a category node.");
|
||||
@@ -955,7 +970,9 @@ public class CreateRulesTests extends RulesRestTest
|
||||
String fakeCategoryId = "bdba5f9f-fake-id22-803b-349bcfd06fd1";
|
||||
RestCompositeConditionDefinitionModel conditions = rulesUtils.createCompositeCondition(List.of(
|
||||
rulesUtils.createCompositeCondition(!INVERTED, List.of(
|
||||
rulesUtils.createSimpleCondition("category", "equals", fakeCategoryId)))));
|
||||
rulesUtils.createSimpleCondition("category", "equals", fakeCategoryId)
|
||||
))
|
||||
));
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
ruleModel.setConditions(conditions);
|
||||
|
||||
@@ -975,7 +992,9 @@ public class CreateRulesTests extends RulesRestTest
|
||||
final String comparator = "greaterthan";
|
||||
RestCompositeConditionDefinitionModel conditions = rulesUtils.createCompositeCondition(List.of(
|
||||
rulesUtils.createCompositeCondition(!INVERTED, List.of(
|
||||
rulesUtils.createSimpleCondition("size", comparator, "500")))));
|
||||
rulesUtils.createSimpleCondition("size", comparator, "500")
|
||||
))
|
||||
));
|
||||
RestRuleModel ruleModel = rulesUtils.createRuleModelWithDefaultValues();
|
||||
ruleModel.setConditions(conditions);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<!-- Resource defaultTransactionIsolation="-1" defaultAutoCommit="false" maxActive="100" initialSize="10" password="alfresco" username="alfresco" url="jdbc:mysql:///alfresco" driverClassName="org.gjt.mm.mysql.Driver" type="javax.sql.DataSource" auth="Container" name="jdbc/dataSource"/-->
|
||||
<Environment override="false" type="java.lang.Boolean" name="properties/startup.enable" description="A flag that globally enables or disables startup of the major Alfresco subsystems." value="true"/>
|
||||
<Environment override="false" type="java.lang.String" name="properties/dir.root" description="The filesystem directory below which content and index data is stored. Should be on a shared disk if this is a clustered installation."/>
|
||||
<Environment override="false" type="java.lang.String" name="properties/hibernate.dialect" description="The fully qualified name of a org.hibernate.dialect.Dialect subclass that allows Hibernate to generate SQL optimized for a particular relational database. Choose from org.hibernate.dialect.DerbyDialect, org.hibernate.dialect.MySQLInnoDBDialect, org.alfresco.repo.domain.hibernate.dialect.AlfrescoOracle9Dialect, org.alfresco.repo.domain.hibernate.dialect.AlfrescoSybaseAnywhereDialect, org.alfresco.repo.domain.hibernate.dialect.SQLServerDialect, org.hibernate.dialect.PostgreSQLDialect"/>
|
||||
<Environment override="false" type="java.lang.String" name="properties/hibernate.dialect" description="The fully qualified name of a org.hibernate.dialect.Dialect subclass that allows Hibernate to generate SQL optimized for a particular relational database. Choose from org.hibernate.dialect.DerbyDialect, org.hibernate.dialect.MySQLInnoDBDialect, org.alfresco.repo.domain.hibernate.dialect.AlfrescoOracle9Dialect, org.alfresco.repo.domain.hibernate.dialect.AlfrescoSybaseAnywhereDialect, org.alfresco.repo.domain.hibernate.dialect.AlfrescoSQLServerDialect, org.hibernate.dialect.PostgreSQLDialect"/>
|
||||
<Environment override="false" type="java.lang.String" name="properties/hibernate.query.substitutions" description="Mapping from tokens in Hibernate queries to SQL tokens. For PostgreSQL, set this to "true TRUE, false FALSE"."/>
|
||||
<Environment override="false" type="java.lang.Boolean" name="properties/hibernate.jdbc.use_get_generated_keys" description="Enable use of JDBC3 PreparedStatement.getGeneratedKeys() to retrieve natively generated keys after insert. Requires JDBC3+ driver. Set to false if your driver has problems with the Hibernate identifier generators. By default, tries to determine the driver capabilities using connection metadata."/>
|
||||
<Environment override="false" type="java.lang.String" name="properties/hibernate.default_schema" description="Qualify unqualified table names with the given schema/tablespace in generated SQL. It may be necessary to set this when the target database has more than one schema."/>
|
||||
|
||||
@@ -500,7 +500,7 @@
|
||||
org.hibernate.dialect.MySQLInnoDBDialect,
|
||||
org.alfresco.repo.domain.hibernate.dialect.AlfrescoOracle9Dialect,
|
||||
org.alfresco.repo.domain.hibernate.dialect.AlfrescoSybaseAnywhereDialect,
|
||||
org.alfresco.repo.domain.hibernate.dialect.SQLServerDialect, org.hibernate.dialect.PostgreSQLDialect</description>
|
||||
org.alfresco.repo.domain.hibernate.dialect.AlfrescoSQLServerDialect, org.hibernate.dialect.PostgreSQLDialect</description>
|
||||
<env-entry-name>properties/hibernate.dialect</env-entry-name>
|
||||
<env-entry-type>java.lang.String</env-entry-type>
|
||||
<env-entry-value/> <!-- Empty value included for JBoss compatibility -->
|
||||
|
||||
@@ -74,7 +74,7 @@ ModuleDetails shareServicesModule = moduleService.getModule("alfresco-share-serv
|
||||
<div class="index-list">
|
||||
<h4><%=descriptorService.getServerDescriptor().getEdition()%></h4>
|
||||
<p></p>
|
||||
<p><a href="https://support.hyland.com/p/alfresco">Online Documentation</a></p>
|
||||
<p><a href="http://docs.alfresco.com/">Online Documentation</a></p>
|
||||
<p></p>
|
||||
<%
|
||||
if (shareServicesModule != null && ModuleInstallState.INSTALLED.equals(shareServicesModule.getInstallState()))
|
||||
|
||||
52
pom.xml
52
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>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Alfresco Community Repo Parent</name>
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
<properties>
|
||||
<acs.version.major>23</acs.version.major>
|
||||
<acs.version.minor>7</acs.version.minor>
|
||||
<acs.version.revision>0</acs.version.revision>
|
||||
<acs.version.minor>4</acs.version.minor>
|
||||
<acs.version.revision>2</acs.version.revision>
|
||||
<acs.version.label />
|
||||
<amp.min.version>${acs.version.major}.0.0</amp.min.version>
|
||||
|
||||
@@ -51,19 +51,19 @@
|
||||
<dependency.alfresco-server-root.version>7.0.1</dependency.alfresco-server-root.version>
|
||||
<dependency.activiti-engine.version>5.23.0</dependency.activiti-engine.version>
|
||||
<dependency.activiti.version>5.23.0</dependency.activiti.version>
|
||||
<dependency.alfresco-transform-core.version>5.2.2</dependency.alfresco-transform-core.version>
|
||||
<dependency.alfresco-transform-service.version>4.2.2</dependency.alfresco-transform-service.version>
|
||||
<dependency.alfresco-transform-core.version>5.1.5</dependency.alfresco-transform-core.version>
|
||||
<dependency.alfresco-transform-service.version>4.1.5</dependency.alfresco-transform-service.version>
|
||||
<dependency.alfresco-greenmail.version>7.0</dependency.alfresco-greenmail.version>
|
||||
<dependency.acs-event-model.version>0.0.33</dependency.acs-event-model.version>
|
||||
|
||||
<dependency.aspectj.version>1.9.22.1</dependency.aspectj.version>
|
||||
<dependency.spring.version>6.2.11</dependency.spring.version>
|
||||
<dependency.spring-security.version>6.4.11</dependency.spring-security.version>
|
||||
<dependency.spring.version>6.1.14</dependency.spring.version>
|
||||
<dependency.spring-security.version>6.3.4</dependency.spring-security.version>
|
||||
<dependency.antlr.version>3.5.3</dependency.antlr.version>
|
||||
<dependency.jackson.version>2.17.2</dependency.jackson.version>
|
||||
<dependency.cxf.version>4.1.2</dependency.cxf.version>
|
||||
<dependency.cxf.version>4.1.0</dependency.cxf.version>
|
||||
<dependency.opencmis.version>1.0.0-jakarta-1</dependency.opencmis.version>
|
||||
<dependency.webscripts.version>10.2</dependency.webscripts.version>
|
||||
<dependency.webscripts.version>9.4</dependency.webscripts.version>
|
||||
<dependency.bouncycastle.version>1.78.1</dependency.bouncycastle.version>
|
||||
<dependency.mockito-core.version>5.14.1</dependency.mockito-core.version>
|
||||
<dependency.assertj.version>3.26.3</dependency.assertj.version>
|
||||
@@ -81,9 +81,9 @@
|
||||
<dependency.slf4j.version>2.0.16</dependency.slf4j.version>
|
||||
<dependency.log4j.version>2.23.1</dependency.log4j.version>
|
||||
<dependency.groovy.version>3.0.22</dependency.groovy.version>
|
||||
<dependency.tika.version>3.2.3</dependency.tika.version>
|
||||
<dependency.tika.version>2.9.2</dependency.tika.version>
|
||||
<dependency.truezip.version>7.7.10</dependency.truezip.version>
|
||||
<dependency.poi.version>5.4.1</dependency.poi.version>
|
||||
<dependency.poi.version>5.3.0</dependency.poi.version>
|
||||
<dependency.jboss.logging.version>3.5.0.Final</dependency.jboss.logging.version>
|
||||
<dependency.camel.version>4.10.2</dependency.camel.version> <!-- when bumping this version, please keep track/sync with included netty.io dependencies -->
|
||||
<dependency.netty.version>4.1.118.Final</dependency.netty.version> <!-- must be in sync with camels transitive dependencies, e.g.: netty-common -->
|
||||
@@ -113,7 +113,7 @@
|
||||
<dependency.jakarta-json-path.version>2.9.0</dependency.jakarta-json-path.version>
|
||||
<dependency.json-smart.version>2.5.2</dependency.json-smart.version>
|
||||
<alfresco.googledrive.version>4.1.0</alfresco.googledrive.version>
|
||||
<alfresco.aos-module.version>3.4.0</alfresco.aos-module.version>
|
||||
<alfresco.aos-module.version>3.2.0</alfresco.aos-module.version>
|
||||
<alfresco.api-explorer.version>23.4.0</alfresco.api-explorer.version> <!-- Also in alfresco-enterprise-share -->
|
||||
|
||||
<alfresco.maven-plugin.version>2.2.0</alfresco.maven-plugin.version>
|
||||
@@ -154,7 +154,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>23.7.0.1</tag>
|
||||
<tag>23.4.2.7</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -170,12 +170,6 @@
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<!-- v1.10 has 0BSD license it must be consulted with Legal -->
|
||||
<dependency>
|
||||
<groupId>org.tukaani</groupId>
|
||||
<artifactId>xz</artifactId>
|
||||
<version>1.9</version>
|
||||
</dependency>
|
||||
<!-- Jakarta... -->
|
||||
<dependency>
|
||||
<groupId>jakarta.xml.bind</groupId>
|
||||
@@ -415,7 +409,7 @@
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
<version>1.11.0</version>
|
||||
<version>1.9.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
@@ -423,9 +417,9 @@
|
||||
<version>1.17.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.18.0</version>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
@@ -445,8 +439,8 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-fileupload2-jakarta-servlet6</artifactId>
|
||||
<version>2.0.0-M4</version>
|
||||
<artifactId>commons-fileupload2-jakarta</artifactId>
|
||||
<version>2.0.0-M1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-net</groupId>
|
||||
@@ -1138,10 +1132,16 @@
|
||||
<exclude>jakarta.xml.soap:jakarta.xml.soap-api:(, 2.0.1)</exclude>
|
||||
<exclude>jakarta.jws:jakarta.jws-api:(, 3.0.0)</exclude>
|
||||
<!-- Enforce ban bouncycastle dependencies other than specified under <includes> section-->
|
||||
<exclude>org.bouncycastle:(,1.81)</exclude>
|
||||
<exclude>org.bouncycastle</exclude>
|
||||
<!-- Enforce one version of Jaxb-->
|
||||
<exclude>com.sun.xml.bind</exclude>
|
||||
</excludes>
|
||||
<includes>
|
||||
<include>org.bouncycastle:bcprov-jdk18on:[1.78.1,)</include>
|
||||
<include>org.bouncycastle:bcmail-jdk18on:[1.78.1,)</include>
|
||||
<include>org.bouncycastle:bcpkix-jdk18on:[1.78.1,)</include>
|
||||
<include>org.bouncycastle:bcutil-jdk18on:[1.78.1,)</include>
|
||||
</includes>
|
||||
</bannedDependencies>
|
||||
</rules>
|
||||
<fail>true</fail>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -31,14 +31,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.owasp.html.PolicyFactory;
|
||||
import org.owasp.html.Sanitizers;
|
||||
import org.springframework.extensions.webscripts.Cache;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.model.ForumModel;
|
||||
import org.alfresco.repo.content.MimetypeMap;
|
||||
@@ -52,6 +44,10 @@ import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.service.namespace.RegexQNamePattern;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.springframework.extensions.webscripts.Cache;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
import org.springframework.extensions.webscripts.WebScriptRequest;
|
||||
|
||||
/**
|
||||
* This class is the controller for the comments.post web script.
|
||||
@@ -70,19 +66,6 @@ public class CommentsPost extends AbstractCommentsWebScript
|
||||
// get json object from request
|
||||
JSONObject json = parseJSON(req);
|
||||
|
||||
// Validating and Sanitizing comment content to prevent XSS
|
||||
String commentContent = getOrNull(json, "content");
|
||||
if (StringUtils.isBlank(commentContent))
|
||||
{
|
||||
throw new IllegalArgumentException("Comment content must not be empty");
|
||||
}
|
||||
else
|
||||
{
|
||||
PolicyFactory policy = Sanitizers.FORMATTING.and(Sanitizers.LINKS);
|
||||
String safeContent = policy.sanitize(commentContent);
|
||||
json.replace("content", safeContent);
|
||||
}
|
||||
|
||||
/* MNT-10231, MNT-9771 fix */
|
||||
this.behaviourFilter.disableBehaviour(nodeRef, ContentModel.ASPECT_AUDITABLE);
|
||||
|
||||
@@ -152,7 +135,7 @@ public class CommentsPost extends AbstractCommentsWebScript
|
||||
{
|
||||
Map<String, Object> result = new HashMap<String, Object>(4, 1.0f);
|
||||
|
||||
String creator = (String) this.nodeService.getProperty(commentNodeRef, ContentModel.PROP_CREATOR);
|
||||
String creator = (String)this.nodeService.getProperty(commentNodeRef, ContentModel.PROP_CREATOR);
|
||||
|
||||
Serializable created = this.nodeService.getProperty(commentNodeRef, ContentModel.PROP_CREATED);
|
||||
Serializable modified = this.nodeService.getProperty(commentNodeRef, ContentModel.PROP_MODIFIED);
|
||||
@@ -160,7 +143,7 @@ public class CommentsPost extends AbstractCommentsWebScript
|
||||
boolean isUpdated = false;
|
||||
if (created instanceof Date && modified instanceof Date)
|
||||
{
|
||||
isUpdated = ((Date) modified).getTime() - ((Date) created).getTime() > 5000;
|
||||
isUpdated = ((Date)modified).getTime() - ((Date)created).getTime() > 5000;
|
||||
}
|
||||
|
||||
// TODO refactor v0 Comments API to use CommentService (see ACE-5437)
|
||||
@@ -246,7 +229,8 @@ public class CommentsPost extends AbstractCommentsWebScript
|
||||
*/
|
||||
private NodeRef createCommentsFolder(final NodeRef nodeRef)
|
||||
{
|
||||
NodeRef commentsFolder = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<NodeRef>() {
|
||||
NodeRef commentsFolder = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<NodeRef>()
|
||||
{
|
||||
public NodeRef doWork() throws Exception
|
||||
{
|
||||
NodeRef commentsFolder = null;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2023 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -34,7 +34,7 @@ import org.alfresco.repo.management.subsystems.ActivateableBean;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationComponent;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationException;
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.repo.security.authentication.external.ExternalUserAuthenticator;
|
||||
import org.alfresco.repo.security.authentication.external.AdminConsoleAuthenticator;
|
||||
import org.alfresco.repo.security.authentication.external.RemoteUserMapper;
|
||||
import org.alfresco.repo.web.auth.AuthenticationListener;
|
||||
import org.alfresco.repo.web.auth.TicketCredentials;
|
||||
@@ -73,11 +73,9 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
|
||||
protected RemoteUserMapper remoteUserMapper;
|
||||
protected AuthenticationComponent authenticationComponent;
|
||||
protected ExternalUserAuthenticator adminConsoleAuthenticator;
|
||||
protected ExternalUserAuthenticator webScriptsHomeAuthenticator;
|
||||
protected AdminConsoleAuthenticator adminConsoleAuthenticator;
|
||||
|
||||
private boolean alwaysAllowBasicAuthForAdminConsole = true;
|
||||
private boolean alwaysAllowBasicAuthForWebScriptsHome = true;
|
||||
List<String> adminConsoleScriptFamilies;
|
||||
long getRemoteUserTimeoutMilliseconds = GET_REMOTE_USER_TIMEOUT_MILLISECONDS_DEFAULT;
|
||||
|
||||
@@ -102,16 +100,6 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
this.alwaysAllowBasicAuthForAdminConsole = alwaysAllowBasicAuthForAdminConsole;
|
||||
}
|
||||
|
||||
public boolean isAlwaysAllowBasicAuthForWebScriptsHome()
|
||||
{
|
||||
return alwaysAllowBasicAuthForWebScriptsHome;
|
||||
}
|
||||
|
||||
public void setAlwaysAllowBasicAuthForWebScriptsHome(boolean alwaysAllowBasicAuthForWebScriptsHome)
|
||||
{
|
||||
this.alwaysAllowBasicAuthForWebScriptsHome = alwaysAllowBasicAuthForWebScriptsHome;
|
||||
}
|
||||
|
||||
public List<String> getAdminConsoleScriptFamilies()
|
||||
{
|
||||
return adminConsoleScriptFamilies;
|
||||
@@ -133,17 +121,11 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
}
|
||||
|
||||
public void setAdminConsoleAuthenticator(
|
||||
ExternalUserAuthenticator adminConsoleAuthenticator)
|
||||
AdminConsoleAuthenticator adminConsoleAuthenticator)
|
||||
{
|
||||
this.adminConsoleAuthenticator = adminConsoleAuthenticator;
|
||||
}
|
||||
|
||||
public void setWebScriptsHomeAuthenticator(
|
||||
ExternalUserAuthenticator webScriptsHomeAuthenticator)
|
||||
{
|
||||
this.webScriptsHomeAuthenticator = webScriptsHomeAuthenticator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator create(WebScriptServletRequest req, WebScriptServletResponse res)
|
||||
{
|
||||
@@ -157,8 +139,6 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
*/
|
||||
public class RemoteUserAuthenticator extends BasicHttpAuthenticator
|
||||
{
|
||||
private static final String WEB_SCRIPTS_BASE_PATH = "org/springframework/extensions/webscripts";
|
||||
|
||||
public RemoteUserAuthenticator(WebScriptServletRequest req, WebScriptServletResponse res, AuthenticationListener listener)
|
||||
{
|
||||
super(req, res, listener);
|
||||
@@ -179,47 +159,24 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
{
|
||||
|
||||
if (servletReq.getServiceMatch() != null &&
|
||||
isAdminConsole(servletReq.getServiceMatch().getWebScript()) && isAdminConsoleAuthenticatorActive())
|
||||
isAdminConsoleWebScript(servletReq.getServiceMatch().getWebScript()) && isAdminConsoleAuthenticatorActive())
|
||||
{
|
||||
userId = getAdminConsoleUser();
|
||||
}
|
||||
else if (servletReq.getServiceMatch() != null &&
|
||||
isWebScriptsHome(servletReq.getServiceMatch().getWebScript()) && isWebScriptsHomeAuthenticatorActive())
|
||||
{
|
||||
userId = getWebScriptsHomeUser();
|
||||
}
|
||||
|
||||
if (userId == null)
|
||||
{
|
||||
if (isAlwaysAllowBasicAuthForAdminConsole())
|
||||
{
|
||||
boolean shouldUseTimeout = shouldUseTimeoutForAdminAccessingAdminConsole(required, isGuest);
|
||||
final boolean useTimeoutForAdminAccessingAdminConsole = shouldUseTimeoutForAdminAccessingAdminConsole(required, isGuest);
|
||||
|
||||
if (shouldUseTimeout && isBasicAuthHeaderPresentForAdmin())
|
||||
if (useTimeoutForAdminAccessingAdminConsole && isBasicAuthHeaderPresentForAdmin())
|
||||
{
|
||||
return callBasicAuthForAdminConsoleOrWebScriptsHomeAccess(required, isGuest);
|
||||
return callBasicAuthForAdminConsoleAccess(required, isGuest);
|
||||
}
|
||||
try
|
||||
{
|
||||
userId = getRemoteUserWithTimeout(shouldUseTimeout);
|
||||
}
|
||||
catch (AuthenticationTimeoutException e)
|
||||
{
|
||||
// return basic auth challenge
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (isAlwaysAllowBasicAuthForWebScriptsHome())
|
||||
{
|
||||
boolean shouldUseTimeout = shouldUseTimeoutForAdminAccessingWebScriptsHome(required, isGuest);
|
||||
|
||||
if (shouldUseTimeout && isBasicAuthHeaderPresentForAdmin())
|
||||
{
|
||||
return callBasicAuthForAdminConsoleOrWebScriptsHomeAccess(required, isGuest);
|
||||
}
|
||||
try
|
||||
{
|
||||
userId = getRemoteUserWithTimeout(shouldUseTimeout);
|
||||
userId = getRemoteUserWithTimeout(useTimeoutForAdminAccessingAdminConsole);
|
||||
}
|
||||
catch (AuthenticationTimeoutException e)
|
||||
{
|
||||
@@ -298,63 +255,38 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
authenticated = super.authenticate(required, isGuest);
|
||||
}
|
||||
}
|
||||
if (!authenticated && servletReq.getServiceMatch() != null)
|
||||
if(!authenticated && servletReq.getServiceMatch() != null &&
|
||||
isAdminConsoleWebScript(servletReq.getServiceMatch().getWebScript()) && isAdminConsoleAuthenticatorActive())
|
||||
{
|
||||
WebScript webScript = servletReq.getServiceMatch().getWebScript();
|
||||
|
||||
if (isAdminConsole(webScript) && isAdminConsoleAuthenticatorActive())
|
||||
{
|
||||
adminConsoleAuthenticator.requestAuthentication(
|
||||
this.servletReq.getHttpServletRequest(),
|
||||
this.servletRes.getHttpServletResponse());
|
||||
}
|
||||
else if (isWebScriptsHome(webScript)
|
||||
&& isWebScriptsHomeAuthenticatorActive())
|
||||
{
|
||||
webScriptsHomeAuthenticator.requestAuthentication(
|
||||
this.servletReq.getHttpServletRequest(),
|
||||
this.servletRes.getHttpServletResponse());
|
||||
}
|
||||
adminConsoleAuthenticator.requestAuthentication(this.servletReq.getHttpServletRequest(), this.servletRes.getHttpServletResponse());
|
||||
}
|
||||
return authenticated;
|
||||
}
|
||||
|
||||
private boolean callBasicAuthForAdminConsoleOrWebScriptsHomeAccess(RequiredAuthentication required, boolean isGuest)
|
||||
private boolean callBasicAuthForAdminConsoleAccess(RequiredAuthentication required, boolean isGuest)
|
||||
{
|
||||
// return REST call, after a timeout/basic auth challenge
|
||||
if (LOGGER.isTraceEnabled())
|
||||
{
|
||||
LOGGER.trace("An Admin Console or WebScripts Home request has come in with Basic Auth headers present for an admin user.");
|
||||
LOGGER.trace("An Admin Console request has come in with Basic Auth headers present for an admin user.");
|
||||
}
|
||||
// In order to prompt for another password, in case it was not entered correctly,
|
||||
// the output of this method should be returned by the calling "authenticate" method;
|
||||
// This would also mean, that once the admin basic auth header is present,
|
||||
// the authentication chain will not be used for access
|
||||
// the authentication chain will not be used for the admin console access
|
||||
return super.authenticate(required, isGuest);
|
||||
}
|
||||
|
||||
private boolean shouldUseTimeoutForAdminAccessingAdminConsole(RequiredAuthentication required, boolean isGuest)
|
||||
{
|
||||
boolean adminConsoleTimeout = RequiredAuthentication.admin.equals(required) && !isGuest &&
|
||||
servletReq.getServiceMatch() != null && isAdminConsole(servletReq.getServiceMatch().getWebScript());
|
||||
boolean useTimeoutForAdminAccessingAdminConsole = RequiredAuthentication.admin.equals(required) && !isGuest &&
|
||||
servletReq.getServiceMatch() != null && isAdminConsoleWebScript(servletReq.getServiceMatch().getWebScript());
|
||||
|
||||
if (LOGGER.isTraceEnabled())
|
||||
{
|
||||
LOGGER.trace("Should ensure that the admins can login with basic auth: " + adminConsoleTimeout);
|
||||
LOGGER.trace("Should ensure that the admins can login with basic auth: " + useTimeoutForAdminAccessingAdminConsole);
|
||||
}
|
||||
return adminConsoleTimeout;
|
||||
}
|
||||
|
||||
private boolean shouldUseTimeoutForAdminAccessingWebScriptsHome(RequiredAuthentication required, boolean isGuest)
|
||||
{
|
||||
boolean adminWebScriptsHomeTimeout = RequiredAuthentication.admin.equals(required) && !isGuest &&
|
||||
servletReq.getServiceMatch() != null && isWebScriptsHome(servletReq.getServiceMatch().getWebScript());
|
||||
|
||||
if (LOGGER.isTraceEnabled())
|
||||
{
|
||||
LOGGER.trace("Should ensure that the admins can login with basic auth: " + adminWebScriptsHomeTimeout);
|
||||
}
|
||||
return adminWebScriptsHomeTimeout;
|
||||
return useTimeoutForAdminAccessingAdminConsole;
|
||||
}
|
||||
|
||||
private boolean isRemoteUserMapperActive()
|
||||
@@ -367,12 +299,7 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
return adminConsoleAuthenticator != null && (!(adminConsoleAuthenticator instanceof ActivateableBean) || ((ActivateableBean) adminConsoleAuthenticator).isActive());
|
||||
}
|
||||
|
||||
private boolean isWebScriptsHomeAuthenticatorActive()
|
||||
{
|
||||
return webScriptsHomeAuthenticator != null && (!(webScriptsHomeAuthenticator instanceof ActivateableBean) || ((ActivateableBean) webScriptsHomeAuthenticator).isActive());
|
||||
}
|
||||
|
||||
protected boolean isAdminConsole(WebScript webScript)
|
||||
protected boolean isAdminConsoleWebScript(WebScript webScript)
|
||||
{
|
||||
if (webScript == null || adminConsoleScriptFamilies == null || webScript.getDescription() == null
|
||||
|| webScript.getDescription().getFamilys() == null)
|
||||
@@ -386,7 +313,7 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
}
|
||||
|
||||
// intersect the "family" sets defined
|
||||
Set<String> families = new HashSet<>(webScript.getDescription().getFamilys());
|
||||
Set<String> families = new HashSet<String>(webScript.getDescription().getFamilys());
|
||||
families.retainAll(adminConsoleScriptFamilies);
|
||||
final boolean isAdminConsole = !families.isEmpty();
|
||||
|
||||
@@ -398,23 +325,6 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
return isAdminConsole;
|
||||
}
|
||||
|
||||
protected boolean isWebScriptsHome(WebScript webScript)
|
||||
{
|
||||
if (webScript == null || webScript.toString() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isWebScriptsHome = webScript.toString().startsWith(WEB_SCRIPTS_BASE_PATH);
|
||||
|
||||
if (LOGGER.isTraceEnabled() && isWebScriptsHome)
|
||||
{
|
||||
LOGGER.trace("Detected a WebScripts Home webscript: " + webScript);
|
||||
}
|
||||
|
||||
return isWebScriptsHome;
|
||||
}
|
||||
|
||||
protected String getRemoteUserWithTimeout(boolean useTimeout) throws AuthenticationTimeoutException
|
||||
{
|
||||
if (!useTimeout)
|
||||
@@ -513,21 +423,7 @@ public class RemoteUserAuthenticatorFactory extends BasicHttpAuthenticatorFactor
|
||||
|
||||
if (isRemoteUserMapperActive())
|
||||
{
|
||||
userId = adminConsoleAuthenticator.getUserId(this.servletReq.getHttpServletRequest(), this.servletRes.getHttpServletResponse());
|
||||
}
|
||||
|
||||
logRemoteUserID(userId);
|
||||
|
||||
return userId;
|
||||
}
|
||||
|
||||
protected String getWebScriptsHomeUser()
|
||||
{
|
||||
String userId = null;
|
||||
|
||||
if (isRemoteUserMapperActive())
|
||||
{
|
||||
userId = webScriptsHomeAuthenticator.getUserId(this.servletReq.getHttpServletRequest(), this.servletRes.getHttpServletResponse());
|
||||
userId = adminConsoleAuthenticator.getAdminConsoleUser(this.servletReq.getHttpServletRequest(), this.servletRes.getHttpServletResponse());
|
||||
}
|
||||
|
||||
logRemoteUserID(userId);
|
||||
|
||||
@@ -28,9 +28,11 @@ package org.alfresco.repo.web.scripts.transfer;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.cmr.transfer.TransferReceiver;
|
||||
import org.apache.commons.fileupload2.core.FileItemInput;
|
||||
import org.apache.commons.fileupload2.core.FileItemInputIterator;
|
||||
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletFileUpload;
|
||||
import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
@@ -39,9 +41,6 @@ import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.extensions.webscripts.WrappingWebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest;
|
||||
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.cmr.transfer.TransferReceiver;
|
||||
|
||||
/**
|
||||
* This command processor is used to receive one or more content files for a given transfer.
|
||||
*
|
||||
@@ -65,9 +64,12 @@ public class PostContentCommandProcessor implements CommandProcessor
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) */
|
||||
* @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco.web.scripts.WebScriptRequest,
|
||||
* org.alfresco.web.scripts.WebScriptResponse)
|
||||
*/
|
||||
public int process(WebScriptRequest req, WebScriptResponse resp)
|
||||
{
|
||||
logger.debug("post content start");
|
||||
@@ -89,7 +91,8 @@ public class PostContentCommandProcessor implements CommandProcessor
|
||||
{
|
||||
current = null;
|
||||
}
|
||||
} while (current != null);
|
||||
}
|
||||
while (current != null);
|
||||
if (webScriptServletRequest == null)
|
||||
{
|
||||
resp.setStatus(Status.STATUS_BAD_REQUEST);
|
||||
@@ -98,7 +101,7 @@ public class PostContentCommandProcessor implements CommandProcessor
|
||||
|
||||
HttpServletRequest servletRequest = webScriptServletRequest.getHttpServletRequest();
|
||||
|
||||
// Read the transfer id from the request
|
||||
//Read the transfer id from the request
|
||||
String transferId = servletRequest.getParameter("transferId");
|
||||
|
||||
if ((transferId == null) || !JakartaServletFileUpload.isMultipartContent(servletRequest))
|
||||
@@ -123,23 +126,23 @@ public class PostContentCommandProcessor implements CommandProcessor
|
||||
}
|
||||
}
|
||||
|
||||
// WebScriptServletRequest alfRequest = (WebScriptServletRequest)req;
|
||||
// String[] names = alfRequest.getParameterNames();
|
||||
// for(String name : names)
|
||||
// {
|
||||
// FormField item = alfRequest.getFileField(name);
|
||||
//
|
||||
// if(item != null)
|
||||
// {
|
||||
// logger.debug("got content Mime Part : " + name);
|
||||
// receiver.saveContent(transferId, item.getName(), item.getInputStream());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //TODO - should this be an exception?
|
||||
// logger.debug("Unable to get content for Mime Part : " + name);
|
||||
// }
|
||||
// }
|
||||
// WebScriptServletRequest alfRequest = (WebScriptServletRequest)req;
|
||||
// String[] names = alfRequest.getParameterNames();
|
||||
// for(String name : names)
|
||||
// {
|
||||
// FormField item = alfRequest.getFileField(name);
|
||||
//
|
||||
// if(item != null)
|
||||
// {
|
||||
// logger.debug("got content Mime Part : " + name);
|
||||
// receiver.saveContent(transferId, item.getName(), item.getInputStream());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //TODO - should this be an exception?
|
||||
// logger.debug("Unable to get content for Mime Part : " + name);
|
||||
// }
|
||||
// }
|
||||
|
||||
logger.debug("success");
|
||||
|
||||
@@ -148,7 +151,7 @@ public class PostContentCommandProcessor implements CommandProcessor
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.debug("exception caught", ex);
|
||||
if (transferId != null)
|
||||
if(transferId != null)
|
||||
{
|
||||
logger.debug("ending transfer", ex);
|
||||
receiver.end(transferId);
|
||||
|
||||
@@ -27,11 +27,15 @@
|
||||
package org.alfresco.repo.web.scripts.transfer;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferCommons;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.cmr.transfer.TransferReceiver;
|
||||
import org.apache.commons.fileupload2.core.FileItemInput;
|
||||
import org.apache.commons.fileupload2.core.FileItemInputIterator;
|
||||
import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletFileUpload;
|
||||
import org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.webscripts.Status;
|
||||
@@ -40,10 +44,6 @@ import org.springframework.extensions.webscripts.WebScriptResponse;
|
||||
import org.springframework.extensions.webscripts.WrappingWebScriptRequest;
|
||||
import org.springframework.extensions.webscripts.servlet.WebScriptServletRequest;
|
||||
|
||||
import org.alfresco.repo.transfer.TransferCommons;
|
||||
import org.alfresco.service.cmr.transfer.TransferException;
|
||||
import org.alfresco.service.cmr.transfer.TransferReceiver;
|
||||
|
||||
/**
|
||||
* This command processor is used to receive the snapshot for a given transfer.
|
||||
*
|
||||
@@ -59,8 +59,8 @@ public class PostSnapshotCommandProcessor implements CommandProcessor
|
||||
private static final String MSG_CAUGHT_UNEXPECTED_EXCEPTION = "transfer_service.receiver.caught_unexpected_exception";
|
||||
|
||||
/* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse) */
|
||||
* @see org.alfresco.repo.web.scripts.transfer.CommandProcessor#process(org.alfresco.web.scripts.WebScriptRequest, org.alfresco.web.scripts.WebScriptResponse)
|
||||
*/
|
||||
public int process(WebScriptRequest req, WebScriptResponse resp)
|
||||
{
|
||||
|
||||
@@ -83,7 +83,8 @@ public class PostSnapshotCommandProcessor implements CommandProcessor
|
||||
{
|
||||
current = null;
|
||||
}
|
||||
} while (current != null);
|
||||
}
|
||||
while (current != null);
|
||||
if (webScriptServletRequest == null)
|
||||
{
|
||||
logger.debug("bad request, not assignable from");
|
||||
@@ -91,11 +92,11 @@ public class PostSnapshotCommandProcessor implements CommandProcessor
|
||||
return Status.STATUS_BAD_REQUEST;
|
||||
}
|
||||
|
||||
// We can't use the WebScriptRequest version of getParameter, since that may cause the content stream
|
||||
// to be parsed. Get hold of the raw HttpServletRequest and work with that.
|
||||
//We can't use the WebScriptRequest version of getParameter, since that may cause the content stream
|
||||
//to be parsed. Get hold of the raw HttpServletRequest and work with that.
|
||||
HttpServletRequest servletRequest = webScriptServletRequest.getHttpServletRequest();
|
||||
|
||||
// Read the transfer id from the request
|
||||
//Read the transfer id from the request
|
||||
String transferId = servletRequest.getParameter("transferId");
|
||||
|
||||
if ((transferId == null) || !JakartaServletFileUpload.isMultipartContent(servletRequest))
|
||||
@@ -135,7 +136,7 @@ public class PostSnapshotCommandProcessor implements CommandProcessor
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.debug("exception caught", ex);
|
||||
if (transferId != null)
|
||||
if(transferId != null)
|
||||
{
|
||||
logger.debug("ending transfer", ex);
|
||||
receiver.end(transferId);
|
||||
@@ -150,8 +151,7 @@ public class PostSnapshotCommandProcessor implements CommandProcessor
|
||||
}
|
||||
|
||||
/**
|
||||
* @param receiver
|
||||
* the receiver to set
|
||||
* @param receiver the receiver to set
|
||||
*/
|
||||
public void setReceiver(TransferReceiver receiver)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2017 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -25,20 +25,6 @@
|
||||
*/
|
||||
package org.alfresco.rest.api.impl;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.query.PagingRequest;
|
||||
import org.alfresco.query.PagingResults;
|
||||
@@ -89,6 +75,19 @@ import org.alfresco.service.cmr.usage.ContentUsageService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.Pair;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Centralises access to people services and maps between representations.
|
||||
@@ -107,7 +106,8 @@ public class PeopleImpl implements People
|
||||
private static final List<QName> EXCLUDED_ASPECTS = Arrays.asList();
|
||||
private static final List<QName> EXCLUDED_PROPS = Arrays.asList();
|
||||
private static final int USERNAME_MAXLENGTH = 100;
|
||||
private static final String[] RESERVED_AUTHORITY_PREFIXES = {
|
||||
private static final String[] RESERVED_AUTHORITY_PREFIXES =
|
||||
{
|
||||
PermissionService.GROUP_PREFIX,
|
||||
PermissionService.ROLE_PREFIX
|
||||
};
|
||||
@@ -223,27 +223,27 @@ public class PeopleImpl implements People
|
||||
public String validatePerson(final String requestedPersonId, boolean validateIsCurrentUser)
|
||||
{
|
||||
String personId = requestedPersonId;
|
||||
if (personId == null)
|
||||
if(personId == null)
|
||||
{
|
||||
throw new InvalidArgumentException("personId is null.");
|
||||
}
|
||||
|
||||
if (personId.equalsIgnoreCase(DEFAULT_USER))
|
||||
if(personId.equalsIgnoreCase(DEFAULT_USER))
|
||||
{
|
||||
personId = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
}
|
||||
|
||||
personId = personService.getUserIdentifier(personId);
|
||||
if (personId == null)
|
||||
if(personId == null)
|
||||
{
|
||||
// Could not find canonical user ID by case-sensitive ID.
|
||||
throw new EntityNotFoundException(requestedPersonId);
|
||||
}
|
||||
|
||||
if (validateIsCurrentUser)
|
||||
if(validateIsCurrentUser)
|
||||
{
|
||||
String currentUserId = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
if (!currentUserId.equalsIgnoreCase(personId))
|
||||
if(!currentUserId.equalsIgnoreCase(personId))
|
||||
{
|
||||
throw new EntityNotFoundException(personId);
|
||||
}
|
||||
@@ -254,7 +254,7 @@ public class PeopleImpl implements People
|
||||
|
||||
protected void processPersonProperties(String userName, final Map<QName, Serializable> nodeProps)
|
||||
{
|
||||
if (!contentUsageService.getEnabled())
|
||||
if(!contentUsageService.getEnabled())
|
||||
{
|
||||
// quota used will always be 0 in this case so remove from the person properties
|
||||
nodeProps.remove(ContentModel.PROP_SIZE_QUOTA);
|
||||
@@ -264,17 +264,18 @@ public class PeopleImpl implements People
|
||||
// The person description is located in a separate content file located at cm:persondescription
|
||||
// "Inline" this data, by removing the cm:persondescription property and adding a temporary property
|
||||
// (Person.PROP_PERSON_DESCRIPTION) containing the actual content as a string.
|
||||
final ContentData personDescription = (ContentData) nodeProps.get(ContentModel.PROP_PERSONDESC);
|
||||
if (personDescription != null)
|
||||
final ContentData personDescription = (ContentData)nodeProps.get(ContentModel.PROP_PERSONDESC);
|
||||
if(personDescription != null)
|
||||
{
|
||||
nodeProps.remove(ContentModel.PROP_PERSONDESC);
|
||||
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>() {
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
ContentReader reader = contentService.getRawReader(personDescription.getContentUrl());
|
||||
if (reader != null && reader.exists())
|
||||
if(reader != null && reader.exists())
|
||||
{
|
||||
String description = reader.getContentString();
|
||||
nodeProps.put(Person.PROP_PERSON_DESCRIPTION, description);
|
||||
@@ -297,7 +298,7 @@ public class PeopleImpl implements People
|
||||
NodeRef avatar = null;
|
||||
personId = validatePerson(personId);
|
||||
NodeRef personNode = personService.getPerson(personId);
|
||||
if (personNode != null)
|
||||
if(personNode != null)
|
||||
{
|
||||
NodeRef avatarOrig = getAvatarOriginal(personNode);
|
||||
avatar = thumbnailService.getThumbnailByName(avatarOrig, ContentModel.PROP_CONTENT, "avatar");
|
||||
@@ -378,7 +379,7 @@ public class PeopleImpl implements People
|
||||
if (mimeType.indexOf("image/") != 0)
|
||||
{
|
||||
throw new InvalidArgumentException(
|
||||
"Uploaded content must be an image (content type determined to be '" + mimeType + "')");
|
||||
"Uploaded content must be an image (content type determined to be '"+mimeType+"')");
|
||||
}
|
||||
|
||||
// create thumbnail synchronously
|
||||
@@ -415,6 +416,7 @@ public class PeopleImpl implements People
|
||||
nodeService.deleteNode(avatarOrigNodeRef);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a full representation of a person.
|
||||
*
|
||||
@@ -457,7 +459,8 @@ public class PeopleImpl implements People
|
||||
final List<PersonService.PersonInfo> page = pagingResult.getPage();
|
||||
int totalItems = pagingResult.getTotalResultCount().getFirst();
|
||||
final String personId = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
List<Person> people = new AbstractList<Person>() {
|
||||
List<Person> people = new AbstractList<Person>()
|
||||
{
|
||||
@Override
|
||||
public Person get(int index)
|
||||
{
|
||||
@@ -510,7 +513,8 @@ public class PeopleImpl implements People
|
||||
processPersonProperties(personId, nodeProps);
|
||||
// TODO this needs to be run as admin but should we do this here?
|
||||
final String pId = personId;
|
||||
Boolean enabled = AuthenticationUtil.runAsSystem(new RunAsWork<Boolean>() {
|
||||
Boolean enabled = AuthenticationUtil.runAsSystem(new RunAsWork<Boolean>()
|
||||
{
|
||||
public Boolean doWork() throws Exception
|
||||
{
|
||||
return authenticationService.getAuthenticationEnabled(pId);
|
||||
@@ -572,7 +576,7 @@ public class PeopleImpl implements People
|
||||
{
|
||||
validateCreatePersonData(person);
|
||||
|
||||
if (!isAdminAuthority())
|
||||
if (! isAdminAuthority())
|
||||
{
|
||||
// note: do an explict check for admin here (since personExists does not throw 403 unlike createPerson,
|
||||
// hence next block would cause 409 to be returned)
|
||||
@@ -623,14 +627,16 @@ public class PeopleImpl implements People
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the description to a content file and store the content URL in ContentModel.PROP_PERSONDESC
|
||||
* Write the description to a content file and store the content URL in
|
||||
* ContentModel.PROP_PERSONDESC
|
||||
*
|
||||
* @param description
|
||||
* @param nodeRef
|
||||
*/
|
||||
private void savePersonDescription(final String description, final NodeRef nodeRef)
|
||||
{
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>() {
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
@@ -672,7 +678,7 @@ public class PeopleImpl implements People
|
||||
{
|
||||
if (username.toUpperCase().startsWith(prefix))
|
||||
{
|
||||
throw new IllegalArgumentException("Username cannot start with the reserved prefix '" + prefix + "'.");
|
||||
throw new IllegalArgumentException("Username cannot start with the reserved prefix '"+prefix+"'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -681,13 +687,13 @@ public class PeopleImpl implements People
|
||||
{
|
||||
if (fieldValue == null)
|
||||
{
|
||||
throw new InvalidArgumentException("Field '" + fieldName + "' is null, but is required.");
|
||||
throw new InvalidArgumentException("Field '"+fieldName+"' is null, but is required.");
|
||||
}
|
||||
|
||||
// belts-and-braces - note: should not see empty string (since converted to null via custom json deserializer)
|
||||
if ((fieldValue instanceof String) && ((String) fieldValue).isEmpty())
|
||||
if ((fieldValue instanceof String) && ((String)fieldValue).isEmpty())
|
||||
{
|
||||
throw new InvalidArgumentException("Field '" + fieldName + "' is empty, but is required.");
|
||||
throw new InvalidArgumentException("Field '"+fieldName+"' is empty, but is required.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,7 +718,7 @@ public class PeopleImpl implements People
|
||||
Boolean isEnabled = person.isEnabled();
|
||||
if (isEnabled != null)
|
||||
{
|
||||
if (!isEnabled && isAdminAuthority(personIdToUpdate))
|
||||
if (isAdminAuthority(personIdToUpdate))
|
||||
{
|
||||
throw new PermissionDeniedException("Admin authority cannot be disabled.");
|
||||
}
|
||||
@@ -760,11 +766,11 @@ public class PeopleImpl implements People
|
||||
});
|
||||
|
||||
// The person service only allows admin users to set the properties by default.
|
||||
if (!properties.isEmpty())
|
||||
if(!properties.isEmpty())
|
||||
{
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>() {
|
||||
@Override
|
||||
public Void doWork() throws Exception
|
||||
AuthenticationUtil.runAsSystem(new RunAsWork<Void>()
|
||||
{
|
||||
@Override public Void doWork() throws Exception
|
||||
{
|
||||
personService.setPersonProperties(personIdToUpdate, properties, false);
|
||||
return null;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -38,19 +38,11 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.query.PagingRequest;
|
||||
import org.alfresco.repo.security.permissions.AccessDeniedException;
|
||||
import org.alfresco.repo.site.SiteModel;
|
||||
import org.alfresco.rest.api.Nodes;
|
||||
import org.alfresco.rest.api.People;
|
||||
@@ -85,6 +77,8 @@ import org.alfresco.util.AlfrescoCollator;
|
||||
import org.alfresco.util.ISO9075;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.alfresco.util.SearchLanguageConversion;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
/**
|
||||
* Queries implementation
|
||||
@@ -94,8 +88,7 @@ import org.alfresco.util.SearchLanguageConversion;
|
||||
*/
|
||||
public class QueriesImpl implements Queries, InitializingBean
|
||||
{
|
||||
private static final Log LOGGER = LogFactory.getLog(QueriesImpl.class);
|
||||
private final static Map<String, QName> NODE_SORT_PARAMS_TO_QNAMES = sortParamsToQNames(
|
||||
private final static Map<String,QName> NODE_SORT_PARAMS_TO_QNAMES = sortParamsToQNames(
|
||||
PARAM_NAME, ContentModel.PROP_NAME,
|
||||
PARAM_CREATEDAT, ContentModel.PROP_CREATED,
|
||||
PARAM_MODIFIEDAT, ContentModel.PROP_MODIFIED);
|
||||
@@ -111,22 +104,23 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
PARAM_SITE_DESCRIPTION, ContentModel.PROP_DESCRIPTION);
|
||||
|
||||
/**
|
||||
* Helper method to build a map of sort parameter names to QNames. This method iterates through the parameters. If a parameter is a String it is assumed to be a sort parameter name and will be followed by a QName to which it maps. If however it is a QName the local name of the OName is used as the sort parameter name.
|
||||
*
|
||||
* @param parameters
|
||||
* to build up the map.
|
||||
* Helper method to build a map of sort parameter names to QNames. This method iterates through
|
||||
* the parameters. If a parameter is a String it is assumed to be a sort parameter name and will
|
||||
* be followed by a QName to which it maps. If however it is a QName the local name of the OName
|
||||
* is used as the sort parameter name.
|
||||
* @param parameters to build up the map.
|
||||
* @return the map
|
||||
*/
|
||||
private static Map<String, QName> sortParamsToQNames(Object... parameters)
|
||||
{
|
||||
Map<String, QName> map = new HashMap<>();
|
||||
for (int i = 0; i < parameters.length; i++)
|
||||
for (int i=0; i<parameters.length; i++)
|
||||
{
|
||||
map.put(
|
||||
parameters[i] instanceof String
|
||||
? (String) parameters[i++]
|
||||
: ((QName) parameters[i]).getLocalName(),
|
||||
(QName) parameters[i]);
|
||||
? (String)parameters[i++]
|
||||
: ((QName)parameters[i]).getLocalName(),
|
||||
(QName)parameters[i]);
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
@@ -179,7 +173,8 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
public CollectionWithPagingInfo<Node> findNodes(Parameters parameters)
|
||||
{
|
||||
SearchService searchService = sr.getSearchService();
|
||||
return new AbstractQuery<Node>(nodeService, searchService) {
|
||||
return new AbstractQuery<Node>(nodeService, searchService)
|
||||
{
|
||||
private final Map<String, UserInfo> mapUserInfo = new HashMap<>(10);
|
||||
|
||||
@Override
|
||||
@@ -210,7 +205,7 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
QName filterNodeTypeQName = nodes.createQName(nodeTypeStr);
|
||||
if (dictionaryService.getType(filterNodeTypeQName) == null)
|
||||
{
|
||||
throw new InvalidArgumentException("Unknown filter nodeType: " + nodeTypeStr);
|
||||
throw new InvalidArgumentException("Unknown filter nodeType: "+nodeTypeStr);
|
||||
}
|
||||
|
||||
query.append(" AND (+TYPE:\"").append(nodeTypeStr).append(("\")"));
|
||||
@@ -253,7 +248,7 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
{
|
||||
// first request for this namespace prefix, get and cache result
|
||||
Collection<String> prefixes = namespaceService.getPrefixes(qname.getNamespaceURI());
|
||||
prefix = !prefixes.isEmpty() ? prefixes.iterator().next() : "";
|
||||
prefix = prefixes.size() != 0 ? prefixes.iterator().next() : "";
|
||||
cache.put(qname.getNamespaceURI(), prefix);
|
||||
}
|
||||
buf.append('/').append(prefix).append(':').append(ISO9075.encode(qname.getLocalName()));
|
||||
@@ -267,6 +262,12 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Node> newList(int capacity)
|
||||
{
|
||||
return new ArrayList<Node>(capacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Node convert(NodeRef nodeRef, List<String> includeParam)
|
||||
{
|
||||
@@ -290,7 +291,8 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
public CollectionWithPagingInfo<Person> findPeople(Parameters parameters)
|
||||
{
|
||||
SearchService searchService = sr.getSearchService();
|
||||
return new AbstractQuery<Person>(nodeService, searchService) {
|
||||
return new AbstractQuery<Person>(nodeService, searchService)
|
||||
{
|
||||
@Override
|
||||
protected void buildQuery(StringBuilder query, String term, SearchParameters sp, String queryTemplateName)
|
||||
{
|
||||
@@ -303,11 +305,18 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
query.append("*\")");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Person> newList(int capacity)
|
||||
{
|
||||
return new ArrayList<Person>(capacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Person convert(NodeRef nodeRef, List<String> includeParam)
|
||||
{
|
||||
String personId = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_USERNAME);
|
||||
return people.getPerson(personId);
|
||||
Person person = people.getPerson(personId);
|
||||
return person;
|
||||
}
|
||||
|
||||
// TODO Do the sort in the query on day. A comment in the code for the V0 API used for live people
|
||||
@@ -321,7 +330,8 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
public CollectionWithPagingInfo<Site> findSites(Parameters parameters)
|
||||
{
|
||||
SearchService searchService = sr.getSearchService();
|
||||
return new AbstractQuery<Site>(nodeService, searchService) {
|
||||
return new AbstractQuery<Site>(nodeService, searchService)
|
||||
{
|
||||
@Override
|
||||
protected void buildQuery(StringBuilder query, String term, SearchParameters sp, String queryTemplateName)
|
||||
{
|
||||
@@ -334,18 +344,28 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
query.append("*\")");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Site> newList(int capacity)
|
||||
{
|
||||
return new ArrayList<>(capacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Site convert(NodeRef nodeRef, List<String> includeParam)
|
||||
{
|
||||
return getSite(siteService.getSite(nodeRef));
|
||||
return getSite(siteService.getSite(nodeRef), true);
|
||||
}
|
||||
|
||||
// note: see also Sites.getSite
|
||||
private Site getSite(SiteInfo siteInfo)
|
||||
private Site getSite(SiteInfo siteInfo, boolean includeRole)
|
||||
{
|
||||
// set the site id to the short name (to deal with case sensitivity issues with using the siteId from the url)
|
||||
String siteId = siteInfo.getShortName();
|
||||
String role = sites.getSiteRole(siteId);
|
||||
String role = null;
|
||||
if(includeRole)
|
||||
{
|
||||
role = sites.getSiteRole(siteId);
|
||||
}
|
||||
return new Site(siteInfo, role);
|
||||
}
|
||||
}.find(parameters, PARAM_TERM, MIN_TERM_LENGTH_SITES, "_SITE", POST_QUERY_SORT, SITE_SORT_PARAMS_TO_QNAMES, new SortColumn(PARAM_SITE_TITLE, true));
|
||||
@@ -395,41 +415,34 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
}
|
||||
|
||||
ResultSet queryResults = null;
|
||||
List<T> collection = null;
|
||||
try
|
||||
{
|
||||
queryResults = searchService.query(sp);
|
||||
|
||||
List<NodeRef> nodeRefs = queryResults.getNodeRefs();
|
||||
|
||||
Map<NodeRef, T>
|
||||
if (sort == POST_QUERY_SORT)
|
||||
{
|
||||
nodeRefs = postQuerySort(parameters, sortParamsToQNames, defaultSortCols, nodeRefs);
|
||||
}
|
||||
|
||||
collection = new LinkedHashMap<>(nodeRefs.size());
|
||||
collection = newList(nodeRefs.size());
|
||||
List<String> includeParam = parameters.getInclude();
|
||||
|
||||
for (NodeRef nodeRef : nodeRefs)
|
||||
{
|
||||
try
|
||||
{
|
||||
T t = convert(nodeRef, includeParam);
|
||||
collection.put(nodeRef, t);
|
||||
}
|
||||
catch (AccessDeniedException ade)
|
||||
{
|
||||
LOGGER.debug("Ignoring search result for nodeRef " + nodeRef + " due to access denied exception", ade);
|
||||
}
|
||||
collection.add(t);
|
||||
}
|
||||
|
||||
if (sort == POST_QUERY_SORT)
|
||||
{
|
||||
List<T> postQuerySortedCollection = postQuerySort(parameters, sortParamsToQNames, defaultSortCols, collection.keySet())
|
||||
.stream()
|
||||
.map(collection::get)
|
||||
.toList();
|
||||
return listPage(postQuerySortedCollection, paging);
|
||||
return listPage(collection, paging);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CollectionWithPagingInfo.asPaged(paging, collection.values(), queryResults.hasMore(), Long.valueOf(queryResults.getNumberFound()).intValue());
|
||||
return CollectionWithPagingInfo.asPaged(paging, collection, queryResults.hasMore(), Long.valueOf(queryResults.getNumberFound()).intValue());
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -442,25 +455,26 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds up the query and is expected to call {@link SearchParameters#setDefaultFieldName(String)} and {@link SearchParameters#addQueryTemplate(String, String)}
|
||||
*
|
||||
* @param query
|
||||
* StringBuilder into which the query should be built.
|
||||
* @param term
|
||||
* to be searched for
|
||||
* @param sp
|
||||
* SearchParameters
|
||||
* Builds up the query and is expected to call {@link SearchParameters#setDefaultFieldName(String)}
|
||||
* and {@link SearchParameters#addQueryTemplate(String, String)}
|
||||
* @param query StringBuilder into which the query should be built.
|
||||
* @param term to be searched for
|
||||
* @param sp SearchParameters
|
||||
* @param queryTemplateName
|
||||
*/
|
||||
protected abstract void buildQuery(StringBuilder query, String term, SearchParameters sp, String queryTemplateName);
|
||||
|
||||
/**
|
||||
* Returns a list of the correct type.
|
||||
* @param capacity of the list
|
||||
* @return a new list.
|
||||
*/
|
||||
protected abstract List<T> newList(int capacity);
|
||||
|
||||
/**
|
||||
* Converts a nodeRef into the an object of the required type.
|
||||
*
|
||||
* @param nodeRef
|
||||
* to be converted
|
||||
* @param includeParam
|
||||
* additional fields to be included
|
||||
* @param nodeRef to be converted
|
||||
* @param includeParam additional fields to be included
|
||||
* @return the object
|
||||
*/
|
||||
protected abstract T convert(NodeRef nodeRef, List<String> includeParam);
|
||||
@@ -470,7 +484,7 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
String term = parameters.getParameter(termName);
|
||||
if (term == null)
|
||||
{
|
||||
throw new InvalidArgumentException("Query '" + termName + "' not specified");
|
||||
throw new InvalidArgumentException("Query '"+termName+"' not specified");
|
||||
}
|
||||
|
||||
term = escapeTerm(term);
|
||||
@@ -491,7 +505,7 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
|
||||
if (cnt < minTermLength)
|
||||
{
|
||||
throw new InvalidArgumentException("Query '" + termName + "' is too short. Must have at least " + minTermLength + " alphanumeric chars");
|
||||
throw new InvalidArgumentException("Query '"+termName+"' is too short. Must have at least "+minTermLength+" alphanumeric chars");
|
||||
}
|
||||
|
||||
return term;
|
||||
@@ -523,7 +537,7 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
QName sortPropQName = sortParamsToQNames.get(sortCol.column);
|
||||
if (sortPropQName == null)
|
||||
{
|
||||
throw new InvalidArgumentException("Invalid sort field: " + sortCol.column);
|
||||
throw new InvalidArgumentException("Invalid sort field: "+sortCol.column);
|
||||
}
|
||||
sp.addSort("@" + sortPropQName, sortCol.asc);
|
||||
}
|
||||
@@ -532,7 +546,7 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
private List<SortColumn> getSorting(Parameters parameters, List<SortColumn> defaultSortCols)
|
||||
{
|
||||
List<SortColumn> sortCols = parameters.getSorting();
|
||||
if (sortCols == null || sortCols.isEmpty())
|
||||
if (sortCols == null || sortCols.size() == 0)
|
||||
{
|
||||
sortCols = defaultSortCols == null ? Collections.emptyList() : defaultSortCols;
|
||||
}
|
||||
@@ -540,18 +554,14 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
}
|
||||
|
||||
protected List<NodeRef> postQuerySort(Parameters parameters, Map<String, QName> sortParamsToQNames,
|
||||
List<SortColumn> defaultSortCols, Set<NodeRef> unsortedNodeRefs)
|
||||
List<SortColumn> defaultSortCols, List<NodeRef> nodeRefs)
|
||||
{
|
||||
final List<SortColumn> sortCols = getSorting(parameters, defaultSortCols);
|
||||
int sortColCount = sortCols.size();
|
||||
|
||||
if (sortColCount == 0)
|
||||
if (sortColCount > 0)
|
||||
{
|
||||
return new ArrayList<>(unsortedNodeRefs);
|
||||
}
|
||||
|
||||
// make copy of nodeRefs because it can be unmodifiable list.
|
||||
List<NodeRef> sortedNodeRefs = new ArrayList<>(unsortedNodeRefs);
|
||||
nodeRefs = new ArrayList<NodeRef>(nodeRefs);
|
||||
|
||||
List<QName> sortPropQNames = new ArrayList<>(sortColCount);
|
||||
for (SortColumn sortCol : sortCols)
|
||||
@@ -559,18 +569,19 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
QName sortPropQName = sortParamsToQNames.get(sortCol.column);
|
||||
if (sortPropQName == null)
|
||||
{
|
||||
throw new InvalidArgumentException("Invalid sort field: " + sortCol.column);
|
||||
throw new InvalidArgumentException("Invalid sort field: "+sortCol.column);
|
||||
}
|
||||
sortPropQNames.add(sortPropQName);
|
||||
}
|
||||
|
||||
final Collator col = AlfrescoCollator.getInstance(I18NUtil.getLocale());
|
||||
Collections.sort(sortedNodeRefs, new Comparator<NodeRef>() {
|
||||
Collections.sort(nodeRefs, new Comparator<NodeRef>()
|
||||
{
|
||||
@Override
|
||||
public int compare(NodeRef n1, NodeRef n2)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < sortCols.size(); i++)
|
||||
for (int i=0; i<sortCols.size(); i++)
|
||||
{
|
||||
SortColumn sortCol = sortCols.get(i);
|
||||
QName sortPropQName = sortPropQNames.get(i);
|
||||
@@ -579,7 +590,7 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
Serializable p2 = getProperty(n2, sortPropQName);
|
||||
|
||||
result = ((p1 instanceof Long) && (p2 instanceof Long)
|
||||
? Long.compare((Long) p1, (Long) p2)
|
||||
? Long.compare((Long)p1, (Long)p2)
|
||||
: col.compare(p1.toString(), p2.toString()))
|
||||
* (sortCol.asc ? 1 : -1);
|
||||
|
||||
@@ -598,8 +609,8 @@ public class QueriesImpl implements Queries, InitializingBean
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return sortedNodeRefs;
|
||||
}
|
||||
return nodeRefs;
|
||||
}
|
||||
|
||||
// note: see also AbstractNodeRelation
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -39,9 +39,6 @@ import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
|
||||
import org.alfresco.repo.action.executer.CheckOutActionExecuter;
|
||||
import org.alfresco.repo.action.executer.CopyActionExecuter;
|
||||
import org.alfresco.repo.action.executer.ImageTransformActionExecuter;
|
||||
@@ -61,6 +58,8 @@ import org.alfresco.rest.framework.core.exceptions.PermissionDeniedException;
|
||||
import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.security.PermissionService;
|
||||
import org.alfresco.service.namespace.NamespaceService;
|
||||
import org.apache.commons.collections.MapUtils;
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
|
||||
/**
|
||||
* This class provides logic for validation of permissions for action parameters which reference node.
|
||||
@@ -68,14 +67,15 @@ import org.alfresco.service.namespace.NamespaceService;
|
||||
public class ActionNodeParameterValidator implements ActionValidator
|
||||
{
|
||||
/**
|
||||
* This list holds action parameter names which require only READ permission on a referenced node That means, all other parameters that reference nodes will require WRITE permission
|
||||
* This list holds action parameter names which require only READ permission on a referenced node
|
||||
* That means, all other parameters that reference nodes will require WRITE permission
|
||||
*/
|
||||
static final Map<String, List<String>> REQUIRE_READ_PERMISSION_PARAMS = Map.of(LinkCategoryActionExecuter.NAME, List.of(LinkCategoryActionExecuter.PARAM_CATEGORY_VALUE));
|
||||
static final Map<String, List<String>> REQUIRE_READ_PERMISSION_PARAMS =
|
||||
Map.of(LinkCategoryActionExecuter.NAME, List.of(LinkCategoryActionExecuter.PARAM_CATEGORY_VALUE));
|
||||
|
||||
static final String NO_PROPER_PERMISSIONS_FOR_NODE = "No proper permissions for node: ";
|
||||
static final String NOT_A_CATEGORY = "Node is not a category ";
|
||||
static final String NOT_A_FOLDER = "Node is not a folder ";
|
||||
static final String NO_LONGER_EXISTS = "%s having Id: %s no longer exists. Please update your rule definition.";
|
||||
|
||||
private final Actions actions;
|
||||
private final NamespaceService namespaceService;
|
||||
@@ -94,8 +94,7 @@ public class ActionNodeParameterValidator implements ActionValidator
|
||||
/**
|
||||
* Validates action parameters that reference nodes against access permissions for executing user.
|
||||
*
|
||||
* @param action
|
||||
* Action to be validated
|
||||
* @param action Action to be validated
|
||||
*/
|
||||
@Override
|
||||
public void validate(Action action)
|
||||
@@ -133,15 +132,7 @@ public class ActionNodeParameterValidator implements ActionValidator
|
||||
.filter(pd -> action.getParams().containsKey(pd.getName()))
|
||||
.forEach(p -> {
|
||||
final String nodeId = Objects.toString(action.getParams().get(p.getName()), Strings.EMPTY);
|
||||
NodeRef nodeRef;
|
||||
try
|
||||
{
|
||||
nodeRef = nodes.validateNode(nodeId);
|
||||
}
|
||||
catch (EntityNotFoundException e)
|
||||
{
|
||||
throw new EntityNotFoundException(String.format(NO_LONGER_EXISTS, p.getDisplayLabel(), nodeId), e);
|
||||
}
|
||||
final NodeRef nodeRef = nodes.validateNode(nodeId);
|
||||
validatePermission(action.getActionDefinitionId(), p.getName(), nodeRef);
|
||||
validateType(action.getActionDefinitionId(), nodeRef);
|
||||
});
|
||||
@@ -172,8 +163,7 @@ public class ActionNodeParameterValidator implements ActionValidator
|
||||
{
|
||||
throw new InvalidArgumentException(NOT_A_FOLDER + nodeRef.getId());
|
||||
}
|
||||
}
|
||||
else if (!nodes.nodeMatches(nodeRef, Set.of(TYPE_CATEGORY), Collections.emptySet()))
|
||||
} else if (!nodes.nodeMatches(nodeRef, Set.of(TYPE_CATEGORY), Collections.emptySet()))
|
||||
{
|
||||
throw new InvalidArgumentException(NOT_A_CATEGORY + nodeRef.getId());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Admin Console
|
||||
admin-console.help=Help
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=Successfully saved values.
|
||||
|
||||
admin-console.host=Host
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Konzole pro spr\u00e1vce
|
||||
admin-console.help=N\u00e1pov\u011bda
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=Hodnoty byly \u00fasp\u011b\u0161n\u011b ulo\u017eeny.
|
||||
|
||||
admin-console.host=Hostitel
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Administrationskonsol
|
||||
admin-console.help=Hj\u00e6lp
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=V\u00e6rdierne blev gemt.
|
||||
|
||||
admin-console.host=V\u00e6rt
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Administratorkonsole
|
||||
admin-console.help=Hilfe
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=Erfolgreich gespeicherte Werte.
|
||||
|
||||
admin-console.host=Host
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Consola de administraci\u00f3n
|
||||
admin-console.help=Ayuda
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=Valores guardados correctamente.
|
||||
|
||||
admin-console.host=Host
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Hallintakonsoli
|
||||
admin-console.help=Ohje
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=Arvot tallennettiin.
|
||||
|
||||
admin-console.host=Is\u00e4nt\u00e4
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Console d'administration
|
||||
admin-console.help=Aide
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=Les valeurs ont bien \u00e9t\u00e9 enregistr\u00e9es.
|
||||
|
||||
admin-console.host=H\u00f4te
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Console di amministrazione
|
||||
admin-console.help=Aiuto
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=I valori sono stati salvati.
|
||||
|
||||
admin-console.host=Host
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=\u7ba1\u7406\u30b3\u30f3\u30bd\u30fc\u30eb
|
||||
admin-console.help=\u30d8\u30eb\u30d7
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=\u5024\u3092\u6b63\u5e38\u306b\u4fdd\u5b58\u3057\u307e\u3057\u305f\u3002
|
||||
|
||||
admin-console.host=\u30db\u30b9\u30c8
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Admin-konsoll
|
||||
admin-console.help=Hjelp
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=Verdier som ble lagret.
|
||||
|
||||
admin-console.host=Vert
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Beheerconsole
|
||||
admin-console.help=Help
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=Waarden zijn opgeslagen.
|
||||
|
||||
admin-console.host=Host
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Konsola administracyjna
|
||||
admin-console.help=Pomoc
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=Warto\u015bci zosta\u0142y zapisane pomy\u015blnie.
|
||||
|
||||
admin-console.host=Host
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Console de administra\u00e7\u00e3o
|
||||
admin-console.help=Ajuda
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=Valores salvos com sucesso.
|
||||
|
||||
admin-console.host=Host
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=\u041a\u043e\u043d\u0441\u043e\u043b\u044c \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430
|
||||
admin-console.help=\u0421\u043f\u0440\u0430\u0432\u043a\u0430
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=\u0423\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f.
|
||||
|
||||
admin-console.host=\u0425\u043e\u0441\u0442
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=Admin-konsol
|
||||
admin-console.help=Hj\u00e4lp
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=V\u00e4rden sparades.
|
||||
|
||||
admin-console.host=V\u00e4rd
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# I18N messages for the Repository Admin Console
|
||||
admin-console.header=\u7ba1\u7406\u63a7\u5236\u53f0
|
||||
admin-console.help=\u5e2e\u52a9
|
||||
admin-console.help-link=https://support.hyland.com/p/alfresco
|
||||
admin-console.help-link=http://docs.alfresco.com/{0}/concepts/ch-administering.html
|
||||
admin-console.success=\u5df2\u6210\u529f\u4fdd\u5b58\u7684\u503c\u3002
|
||||
|
||||
admin-console.host=\u4e3b\u673a
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
<#macro page title readonly=false controller=DEFAULT_CONTROLLER!"/admin" params="" dialog=false>
|
||||
<#assign FORM_ID="admin-jmx-form" />
|
||||
<#if server.edition == "Community">
|
||||
<#assign docsEdition = "/Alfresco-Content-Services-Community-Edition/" + server.getVersionMajor() + "." + server.getVersionMinor() + "/Alfresco-Content-Services-Community-Edition" />
|
||||
<#assign docsEdition = "community" />
|
||||
<#elseif server.edition == "Enterprise" >
|
||||
<#assign docsEdition = "/Alfresco-Content-Services/" + server.getVersionMajor() + "." + server.getVersionMinor() + "/Alfresco-Content-Services" />
|
||||
<#assign docsEdition = server.getVersionMajor() + "." + server.getVersionMinor() />
|
||||
</#if>
|
||||
<#if metadata??>
|
||||
<#assign HOSTNAME>${msg("admin-console.host")}: ${metadata.hostname}</#assign>
|
||||
|
||||
@@ -214,13 +214,9 @@
|
||||
<property name="authenticationListener" ref="webScriptAuthenticationListener"/>
|
||||
<property name="remoteUserMapper" ref="RemoteUserMapper" />
|
||||
<property name="adminConsoleAuthenticator" ref="AdminConsoleAuthenticator" />
|
||||
<property name="webScriptsHomeAuthenticator" ref="WebScriptsHomeAuthenticator" />
|
||||
<property name="alwaysAllowBasicAuthForAdminConsole">
|
||||
<value>${authentication.alwaysAllowBasicAuthForAdminConsole.enabled}</value>
|
||||
</property>
|
||||
<property name="alwaysAllowBasicAuthForWebScriptsHome">
|
||||
<value>${authentication.alwaysAllowBasicAuthForWebScriptsHome.enabled}</value>
|
||||
</property>
|
||||
<property name="getRemoteUserTimeoutMilliseconds">
|
||||
<value>${authentication.getRemoteUserTimeoutMilliseconds}</value>
|
||||
</property>
|
||||
|
||||
@@ -25,20 +25,6 @@
|
||||
*/
|
||||
package org.alfresco.rest.api.tests;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||
import org.alfresco.rest.AbstractSingleNetworkSiteTest;
|
||||
import org.alfresco.rest.api.Queries;
|
||||
@@ -50,12 +36,27 @@ import org.alfresco.service.cmr.repository.NodeRef;
|
||||
import org.alfresco.service.cmr.search.SearchParameters;
|
||||
import org.alfresco.service.cmr.site.SiteService;
|
||||
import org.alfresco.service.cmr.site.SiteVisibility;
|
||||
import org.alfresco.util.testing.category.LuceneTests;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.experimental.categories.Category;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
/**
|
||||
* V1 REST API tests for pre-defined 'live' search Queries on Sites
|
||||
* V1 REST API tests for pre-defined 'live' search Queries on Sites
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@literal <host>:<port>/alfresco/api/<networkId>/public/alfresco/versions/1/queries/sites}</li>
|
||||
* <li> {@literal <host>:<port>/alfresco/api/<networkId>/public/alfresco/versions/1/queries/sites} </li>
|
||||
* </ul>
|
||||
*
|
||||
* @author janv
|
||||
@@ -71,7 +72,7 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
public void setup() throws Exception
|
||||
{
|
||||
super.setup();
|
||||
siteService = (SiteService) applicationContext.getBean("SiteService");
|
||||
siteService = (SiteService)applicationContext.getBean("SiteService");
|
||||
}
|
||||
|
||||
// Note expectedIds defaults to ids
|
||||
@@ -85,7 +86,7 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
}
|
||||
|
||||
dummySearchServiceQueryNodeRefs.clear();
|
||||
for (String id : ids)
|
||||
for (String id: ids)
|
||||
{
|
||||
NodeRef nodeRef = getNodeRef(id);
|
||||
dummySearchServiceQueryNodeRefs.add(nodeRef);
|
||||
@@ -97,7 +98,7 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
if (expectedStatus == 200)
|
||||
{
|
||||
String termWithEscapedAsterisks = term.replaceAll("\\*", "\\\\*");
|
||||
String expectedQuery = "TYPE:\"{http://www.alfresco.org/model/site/1.0}site\" AND (\"*" + termWithEscapedAsterisks + "*\")";
|
||||
String expectedQuery = "TYPE:\"{http://www.alfresco.org/model/site/1.0}site\" AND (\"*"+ termWithEscapedAsterisks +"*\")";
|
||||
ArgumentCaptor<SearchParameters> searchParametersCaptor = ArgumentCaptor.forClass(SearchParameters.class);
|
||||
verify(mockSearchService, times(++callCountToMockSearchService)).query(searchParametersCaptor.capture());
|
||||
SearchParameters parameters = searchParametersCaptor.getValue();
|
||||
@@ -108,11 +109,11 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
|
||||
if (orderBy != null)
|
||||
{
|
||||
for (int i = 0; i < expectedIds.length; i++)
|
||||
for (int i=0; i<expectedIds.length; i++)
|
||||
{
|
||||
String id = expectedIds[i];
|
||||
String actualId = sites.get(i).getId();
|
||||
assertEquals("Order " + i + ":", id, actualId);
|
||||
assertEquals("Order "+i+":", id, actualId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,16 +122,14 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
/**
|
||||
* Tests basic api for nodes live search sites - metadata (id, title, description)
|
||||
*
|
||||
* <p>
|
||||
* GET:
|
||||
* </p>
|
||||
* <p>GET:</p>
|
||||
* {@literal <host>:<port>/alfresco/api/<networkId>/public/alfresco/versions/1/queries/sites}
|
||||
*/
|
||||
@Test
|
||||
public void testLiveSearchSites() throws Exception
|
||||
{
|
||||
setRequestContext(user1);
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(user1);
|
||||
|
||||
int sCount = 5;
|
||||
assertTrue(sCount > 4); // as relied on by test below
|
||||
|
||||
@@ -156,8 +155,8 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
{
|
||||
String num = String.format("%05d", i);
|
||||
|
||||
charValue = charValue + 1;
|
||||
siteI = siteI + String.valueOf((char) charValue);
|
||||
charValue = charValue+1;
|
||||
siteI = siteI + String.valueOf((char)charValue);
|
||||
|
||||
String siteId = siteI + num + RUNID;
|
||||
String siteTitle = siteT + num + siteT;
|
||||
@@ -231,11 +230,7 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
|
||||
private NodeRef getNodeRef(String createdSiteId)
|
||||
{
|
||||
// Created sites do not return NodeRefs to the caller so we need to get the NodeRef from the siteService.
|
||||
// Temporarily as admin we will get NodeRefs to handle ACL authorization.
|
||||
String userUnderTest = AuthenticationUtil.getFullyAuthenticatedUser();
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(DEFAULT_ADMIN);
|
||||
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(user1);
|
||||
// The following call to siteService.getSite(createdSiteId).getNodeRef() returns a NodeRef like:
|
||||
// workspace://SpacesStore/9db76769-96de-4de4-bdb4-a127130af362
|
||||
// We call tenantService.getName(nodeRef) to get a fully qualified NodeRef as Solr returns this.
|
||||
@@ -243,8 +238,6 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
// workspace://@org.alfresco.rest.api.tests.queriespeopleapitest@SpacesStore/9db76769-96de-4de4-bdb4-a127130af362
|
||||
NodeRef nodeRef = siteService.getSite(createdSiteId).getNodeRef();
|
||||
nodeRef = tenantService.getName(nodeRef);
|
||||
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(userUnderTest);
|
||||
return nodeRef;
|
||||
}
|
||||
|
||||
@@ -252,7 +245,7 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
public void testLiveSearchSites_SortPage() throws Exception
|
||||
{
|
||||
setRequestContext(user1);
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(user1);
|
||||
|
||||
List<String> siteIds = new ArrayList<>(5);
|
||||
|
||||
try
|
||||
@@ -262,11 +255,11 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
Paging paging = getPaging(0, 100);
|
||||
|
||||
// create site
|
||||
String s1 = createSite("siABCDEF" + RUNID, "ABCDEF DEF", "sdABCDEF", SiteVisibility.PRIVATE, 201).getId();
|
||||
String s2 = createSite("siABCD" + RUNID, "ABCD DEF", "sdABCD", SiteVisibility.PRIVATE, 201).getId();
|
||||
String s3 = createSite("siABCDE" + RUNID, "ABCDE DEF", "sdABCDE", SiteVisibility.PRIVATE, 201).getId();
|
||||
String s4 = createSite("siAB" + RUNID, "AB DEF", "sdAB", SiteVisibility.PRIVATE, 201).getId();
|
||||
String s5 = createSite("siABC" + RUNID, "ABC DEF", "sdABC", SiteVisibility.PRIVATE, 201).getId();
|
||||
String s1 = createSite("siABCDEF"+RUNID, "ABCDEF DEF", "sdABCDEF", SiteVisibility.PRIVATE, 201).getId();
|
||||
String s2 = createSite("siABCD"+RUNID, "ABCD DEF", "sdABCD", SiteVisibility.PRIVATE, 201).getId();
|
||||
String s3 = createSite("siABCDE"+RUNID, "ABCDE DEF", "sdABCDE", SiteVisibility.PRIVATE, 201).getId();
|
||||
String s4 = createSite("siAB"+RUNID, "AB DEF", "sdAB", SiteVisibility.PRIVATE, 201).getId();
|
||||
String s5 = createSite("siABC"+RUNID, "ABC DEF", "sdABC", SiteVisibility.PRIVATE, 201).getId();
|
||||
|
||||
// test sort order
|
||||
{
|
||||
@@ -283,9 +276,9 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
// basic paging tests
|
||||
{
|
||||
// sort order - title desc
|
||||
checkApiCall("siAB", "title desc", getPaging(0, 2), 200, new String[]{s1, s3}, s1, s3, s2, s5, s4);
|
||||
checkApiCall("siAB", "title desc", getPaging(2, 2), 200, new String[]{s2, s5}, s1, s3, s2, s5, s4);
|
||||
checkApiCall("siAB", "title desc", getPaging(4, 2), 200, new String[]{s4}, s1, s3, s2, s5, s4);
|
||||
checkApiCall("siAB", "title desc", getPaging(0, 2), 200, new String[] {s1, s3}, s1, s3, s2, s5, s4);
|
||||
checkApiCall("siAB", "title desc", getPaging(2, 2), 200, new String[] {s2, s5}, s1, s3, s2, s5, s4);
|
||||
checkApiCall("siAB", "title desc", getPaging(4, 2), 200, new String[] {s4}, s1, s3, s2, s5, s4);
|
||||
}
|
||||
|
||||
// -ve tests
|
||||
@@ -312,51 +305,6 @@ public class QueriesSitesApiTest extends AbstractSingleNetworkSiteTest
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the search service do not support ACL filtering, then the Queries API should handle the response to exclude private sites and potential unauthorized error when building response.
|
||||
*/
|
||||
@Test
|
||||
public void testLiveSearchExcludesPrivateSites() throws Exception
|
||||
{
|
||||
String publicSiteId = null;
|
||||
String privateSiteId = null;
|
||||
try
|
||||
{
|
||||
// given
|
||||
setRequestContext(null, DEFAULT_ADMIN, DEFAULT_ADMIN_PWD);
|
||||
createUser("bartender");
|
||||
|
||||
publicSiteId = createSite("samePrefixPublicSite", "samePrefixPublicSite", "Visible to all users", SiteVisibility.PUBLIC, 201).getId();
|
||||
privateSiteId = createSite("samePrefixPrivateSite", "samePrefixPrivateSite", "Hidden from bartender", SiteVisibility.PRIVATE, 201).getId();
|
||||
|
||||
String[] searchResults = {publicSiteId, privateSiteId};
|
||||
String[] expectedSites = {publicSiteId};
|
||||
|
||||
// when
|
||||
setRequestContext(null, "bartender", "password");
|
||||
AuthenticationUtil.setFullyAuthenticatedUser("bartender");
|
||||
|
||||
// then
|
||||
checkApiCall("samePrefix", null, getPaging(0, 100), 200, expectedSites, searchResults);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// cleanup
|
||||
AuthenticationUtil.setFullyAuthenticatedUser(DEFAULT_ADMIN);
|
||||
setRequestContext(null, DEFAULT_ADMIN, DEFAULT_ADMIN_PWD);
|
||||
if (publicSiteId != null)
|
||||
{
|
||||
deleteSite(publicSiteId, true, 204);
|
||||
}
|
||||
if (privateSiteId != null)
|
||||
{
|
||||
deleteSite(privateSiteId, true, 204);
|
||||
}
|
||||
deleteUser("bartender", null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScope()
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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
|
||||
@@ -212,7 +212,7 @@ public class ProcessesImplTest extends TestCase implements RecognizedParamsExtra
|
||||
{
|
||||
// the tests are always run on PostgreSQL only
|
||||
// Dialect dialect = (Dialect) applicationContext.getBean("dialect");
|
||||
// if (dialect instanceof SQLServerDialect)
|
||||
// if (dialect instanceof AlfrescoSQLServerDialect)
|
||||
// {
|
||||
// REPO-1104: we do not run this test on MS SQL server because it will fail
|
||||
// until the Activiti defect related to REPO-1104 will be fixed
|
||||
|
||||
@@ -27,7 +27,7 @@ to integrate with a number of external Authentication providers including
|
||||
* https://github.com/Alfresco/alfresco-data-model/tree/master/src/main/java/org/alfresco/repo/security/authentication
|
||||
* License: LGPL
|
||||
* Issue Tracker Link: https://issues.alfresco.com/jira/issues/?jql=project%3DREPO
|
||||
* Documentation Link: https://support.hyland.com/r/Alfresco/Alfresco-Content-Services-Community-Edition/23.4/Alfresco-Content-Services-Community-Edition/Administer/Manage-Security/Authentication-and-sync
|
||||
* Documentation Link: http://docs.alfresco.com/5.2/concepts/auth-intro.html
|
||||
* Contribution Model: Alfresco Open Source
|
||||
***
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* Source Code Link:m https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/
|
||||
* License: LGPL
|
||||
* Issue Tracker Link: https://issues.alfresco.com/jira/secure/RapidBoard.jspa?projectKey=REPO&useStoredSettings=true&rapidView=379
|
||||
* Documentation Link: https://support.hyland.com/r/Alfresco/Alfresco-Content-Services/23.4/Alfresco-Content-Services/Configure/Repository/About-Versioning
|
||||
* Documentation Link: http://docs.alfresco.com/5.1/concepts/versioning.html
|
||||
* Contribution Model: Alfresco publishes the source code and will review proposed patch requests
|
||||
***
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>23.7.0.1</version>
|
||||
<version>23.4.2.7</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
@@ -85,7 +85,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-fileupload2-jakarta-servlet6</artifactId>
|
||||
<artifactId>commons-fileupload2-jakarta</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
@@ -94,6 +94,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.17.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
@@ -741,6 +742,10 @@
|
||||
<artifactId>reflections</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -31,7 +31,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.alfresco.repo.action.ParameterDefinitionImpl;
|
||||
import org.alfresco.repo.action.access.ActionAccessRestriction;
|
||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||
import org.alfresco.service.cmr.action.Action;
|
||||
import org.alfresco.service.cmr.action.ParameterDefinition;
|
||||
@@ -66,8 +65,7 @@ public class AddFeaturesActionExecuter extends ActionExecuterAbstractBase
|
||||
/**
|
||||
* Set the node service
|
||||
*
|
||||
* @param nodeService
|
||||
* the node service
|
||||
* @param nodeService the node service
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
@@ -77,8 +75,7 @@ public class AddFeaturesActionExecuter extends ActionExecuterAbstractBase
|
||||
/**
|
||||
* Set the transaction service
|
||||
*
|
||||
* @param transactionService
|
||||
* the transaction service
|
||||
* @param transactionService the transaction service
|
||||
*/
|
||||
public void setTransactionService(TransactionService transactionService)
|
||||
{
|
||||
@@ -102,13 +99,14 @@ public class AddFeaturesActionExecuter extends ActionExecuterAbstractBase
|
||||
if (this.nodeService.exists(actionedUponNodeRef))
|
||||
{
|
||||
transactionService.getRetryingTransactionHelper().doInTransaction(
|
||||
new RetryingTransactionCallback<Void>() {
|
||||
new RetryingTransactionCallback<Void>()
|
||||
{
|
||||
public Void execute() throws Throwable
|
||||
{
|
||||
Map<QName, Serializable> properties = new HashMap<QName, Serializable>();
|
||||
QName aspectQName = null;
|
||||
|
||||
if (!nodeService.exists(actionedUponNodeRef))
|
||||
if(! nodeService.exists(actionedUponNodeRef))
|
||||
{
|
||||
// Node has gone away, skip
|
||||
return null;
|
||||
@@ -116,12 +114,11 @@ public class AddFeaturesActionExecuter extends ActionExecuterAbstractBase
|
||||
|
||||
// Build the aspect details
|
||||
Map<String, Serializable> paramValues = ruleAction.getParameterValues();
|
||||
removeActionContextParameter(paramValues);
|
||||
for (Map.Entry<String, Serializable> entry : paramValues.entrySet())
|
||||
{
|
||||
if (entry.getKey().equals(PARAM_ASPECT_NAME) == true)
|
||||
{
|
||||
aspectQName = (QName) entry.getValue();
|
||||
aspectQName = (QName)entry.getValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -136,7 +133,8 @@ public class AddFeaturesActionExecuter extends ActionExecuterAbstractBase
|
||||
nodeService.addAspect(actionedUponNodeRef, aspectQName, properties);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,11 +147,4 @@ public class AddFeaturesActionExecuter extends ActionExecuterAbstractBase
|
||||
paramList.add(new ParameterDefinitionImpl(PARAM_ASPECT_NAME, DataTypeDefinition.QNAME, true, getParamDisplayLabel(PARAM_ASPECT_NAME), false, "ac-aspects"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove actionContext from the parameter values to declassify as an adhoc property
|
||||
*/
|
||||
private void removeActionContextParameter(Map<String, Serializable> paramValues)
|
||||
{
|
||||
paramValues.remove(ActionAccessRestriction.ACTION_CONTEXT_PARAM_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2022 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -41,11 +41,6 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipException;
|
||||
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
import org.apache.commons.compress.utils.InputStreamStatistics;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import org.alfresco.error.AlfrescoRuntimeException;
|
||||
import org.alfresco.model.ApplicationModel;
|
||||
import org.alfresco.model.ContentModel;
|
||||
@@ -58,7 +53,6 @@ import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
|
||||
import org.alfresco.service.cmr.model.FileExistsException;
|
||||
import org.alfresco.service.cmr.model.FileFolderService;
|
||||
import org.alfresco.service.cmr.model.FileInfo;
|
||||
import org.alfresco.service.cmr.model.FolderExistsException;
|
||||
import org.alfresco.service.cmr.repository.ContentReader;
|
||||
import org.alfresco.service.cmr.repository.ContentService;
|
||||
import org.alfresco.service.cmr.repository.ContentWriter;
|
||||
@@ -68,13 +62,16 @@ import org.alfresco.service.cmr.view.ImporterService;
|
||||
import org.alfresco.service.cmr.view.Location;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
import org.alfresco.util.TempFileProvider;
|
||||
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
|
||||
import org.apache.commons.compress.archivers.zip.ZipFile;
|
||||
import org.apache.commons.compress.utils.InputStreamStatistics;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* Importer action executor
|
||||
*
|
||||
* @author gavinc
|
||||
*/
|
||||
@SuppressWarnings("PMD.PreserveStackTrace")
|
||||
public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
public static final String NAME = "import";
|
||||
@@ -113,8 +110,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
/**
|
||||
* Sets the ImporterService to use
|
||||
*
|
||||
* @param importerService
|
||||
* The ImporterService
|
||||
* @param importerService The ImporterService
|
||||
*/
|
||||
public void setImporterService(ImporterService importerService)
|
||||
{
|
||||
@@ -124,8 +120,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
/**
|
||||
* Sets the NodeService to use
|
||||
*
|
||||
* @param nodeService
|
||||
* The NodeService
|
||||
* @param nodeService The NodeService
|
||||
*/
|
||||
public void setNodeService(NodeService nodeService)
|
||||
{
|
||||
@@ -135,8 +130,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
/**
|
||||
* Sets the ContentService to use
|
||||
*
|
||||
* @param contentService
|
||||
* The ContentService
|
||||
* @param contentService The ContentService
|
||||
*/
|
||||
public void setContentService(ContentService contentService)
|
||||
{
|
||||
@@ -146,8 +140,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
/**
|
||||
* Sets the FileFolderService to use
|
||||
*
|
||||
* @param fileFolderService
|
||||
* The FileFolderService
|
||||
* @param fileFolderService The FileFolderService
|
||||
*/
|
||||
public void setFileFolderService(FileFolderService fileFolderService)
|
||||
{
|
||||
@@ -163,8 +156,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
}
|
||||
|
||||
/**
|
||||
* @param highByteZip
|
||||
* the encoding switch for high-byte ZIP filenames to set
|
||||
* @param highByteZip the encoding switch for high-byte ZIP filenames to set
|
||||
*/
|
||||
public void setHighByteZip(boolean highByteZip)
|
||||
{
|
||||
@@ -172,8 +164,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ratioThreshold
|
||||
* the compression ratio threshold for Zip bomb detection
|
||||
* @param ratioThreshold the compression ratio threshold for Zip bomb detection
|
||||
*/
|
||||
public void setRatioThreshold(long ratioThreshold)
|
||||
{
|
||||
@@ -181,10 +172,10 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets a value for the uncompressed bytes limit. If the string does not {@link Long#parseLong(String) parse} to a java long.
|
||||
* This method sets a value for the uncompressed bytes limit. If the string does not {@link Long#parseLong(String) parse} to a
|
||||
* java long.
|
||||
*
|
||||
* @param limit
|
||||
* a String representing a valid Java long.
|
||||
* @param limit a String representing a valid Java long.
|
||||
*/
|
||||
public void setUncompressedBytesLimit(String limit)
|
||||
{
|
||||
@@ -213,7 +204,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
ContentReader reader = this.contentService.getReader(actionedUponNodeRef, ContentModel.PROP_CONTENT);
|
||||
if (reader != null)
|
||||
{
|
||||
NodeRef importDest = (NodeRef) ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER);
|
||||
NodeRef importDest = (NodeRef)ruleAction.getParameterValue(PARAM_DESTINATION_FOLDER);
|
||||
if (MimetypeMap.MIMETYPE_ACP.equals(reader.getMimetype()))
|
||||
{
|
||||
// perform an import of an Alfresco ACP file (special format ZIP structure)
|
||||
@@ -226,7 +217,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
reader.getContent(zipFile);
|
||||
|
||||
ACPImportPackageHandler importHandler = new ACPImportPackageHandler(zipFile,
|
||||
(String) ruleAction.getParameterValue(PARAM_ENCODING));
|
||||
(String)ruleAction.getParameterValue(PARAM_ENCODING));
|
||||
|
||||
this.importerService.importView(importHandler, new Location(importDest), null, null);
|
||||
}
|
||||
@@ -311,10 +302,8 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
/**
|
||||
* Recursively import a directory structure into the specified root node
|
||||
*
|
||||
* @param dir
|
||||
* The directory of files and folders to import
|
||||
* @param root
|
||||
* The root node to import into
|
||||
* @param dir The directory of files and folders to import
|
||||
* @param root The root node to import into
|
||||
*/
|
||||
private void importDirectory(String dir, NodeRef root)
|
||||
{
|
||||
@@ -368,11 +357,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
catch (FileExistsException e)
|
||||
{
|
||||
// TODO: add failed file info to status message?
|
||||
if (e.getType().equalsIgnoreCase("folder"))
|
||||
{
|
||||
throw new FolderExistsException(root, file.getName());
|
||||
}
|
||||
throw e;
|
||||
throw new AlfrescoRuntimeException("Failed to process ZIP file.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,10 +376,8 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
/**
|
||||
* Extract the file and folder structure of a ZIP file into the specified directory
|
||||
*
|
||||
* @param archive
|
||||
* The ZIP archive to extract
|
||||
* @param extractDir
|
||||
* The directory to extract into
|
||||
* @param archive The ZIP archive to extract
|
||||
* @param extractDir The directory to extract into
|
||||
*/
|
||||
public static void extractFile(ZipFile archive, String extractDir)
|
||||
{
|
||||
@@ -404,12 +387,9 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
/**
|
||||
* Extract the file and folder structure of a ZIP file into the specified directory using a progress tracker
|
||||
*
|
||||
* @param archive
|
||||
* The ZIP archive to extract
|
||||
* @param extractDir
|
||||
* The directory to extract into
|
||||
* @param tracker
|
||||
* The extraction progress tracker to check against during the extraction process
|
||||
* @param archive The ZIP archive to extract
|
||||
* @param extractDir The directory to extract into
|
||||
* @param tracker The extraction progress tracker to check against during the extraction process
|
||||
*/
|
||||
public static void extractFile(ZipFile archive, String extractDir, ExtractionProgressTracker tracker)
|
||||
{
|
||||
@@ -427,7 +407,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
ZipArchiveEntry entry = e.nextElement();
|
||||
if (!entry.isDirectory())
|
||||
{
|
||||
fileName = StringUtils.stripAccents(entry.getName()).replaceAll("\\?", "_");
|
||||
fileName = StringUtils.stripAccents(entry.getName()).replaceAll("\\?","_");
|
||||
fileName = fileName.replace('/', File.separatorChar);
|
||||
|
||||
if (fileName.startsWith("/") || fileName.indexOf(":" + File.separator) == 1 || fileName.contains(".." + File.separator))
|
||||
@@ -441,8 +421,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
if (parent != null)
|
||||
{
|
||||
File parentFile = new File(parent);
|
||||
if (!parentFile.exists())
|
||||
parentFile.mkdirs();
|
||||
if (!parentFile.exists()) parentFile.mkdirs();
|
||||
}
|
||||
|
||||
try (InputStream zis = archive.getInputStream(entry);
|
||||
@@ -462,7 +441,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
}
|
||||
else
|
||||
{
|
||||
File newdir = new File(extractDir + StringUtils.stripAccents(entry.getName()).replaceAll("\\?", "_"));
|
||||
File newdir = new File(extractDir + entry.getName());
|
||||
newdir.mkdirs();
|
||||
}
|
||||
}
|
||||
@@ -484,8 +463,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
/**
|
||||
* Recursively delete a dir of files and directories
|
||||
*
|
||||
* @param dir
|
||||
* directory to delete
|
||||
* @param dir directory to delete
|
||||
*/
|
||||
public static void deleteDir(File dir)
|
||||
{
|
||||
@@ -500,10 +478,8 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
for (File file : files)
|
||||
{
|
||||
if (file.isFile())
|
||||
file.delete();
|
||||
else
|
||||
deleteDir(file);
|
||||
if (file.isFile()) file.delete();
|
||||
else deleteDir(file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,7 +525,8 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase
|
||||
{
|
||||
void reportProgress(long compressedBytesCount, long uncompressedBytesCount);
|
||||
|
||||
ExtractionProgressTracker NONE = new ExtractionProgressTracker() {
|
||||
ExtractionProgressTracker NONE = new ExtractionProgressTracker()
|
||||
{
|
||||
@Override
|
||||
public void reportProgress(long compressedBytesCount, long uncompressedBytesCount)
|
||||
{
|
||||
|
||||
@@ -975,6 +975,8 @@ public class AuditComponentImpl implements AuditComponent
|
||||
@Override
|
||||
public int getAuditEntriesCountByAppAndProperties(String applicationName, AuditQueryParameters parameters)
|
||||
{
|
||||
org.alfresco.repo.domain.audit.AuditQueryParameters dbParameters = new org.alfresco.repo.domain.audit.AuditQueryParameters();
|
||||
|
||||
return auditDAO.getAuditEntriesCountByAppAndProperties(applicationName, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -36,7 +36,8 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
|
||||
import org.alfresco.service.namespace.QName;
|
||||
|
||||
/**
|
||||
* Class holding properties associated with the <b>sys:referenceable</b> aspect. This aspect is common enough to warrant direct inclusion on the <b>Node</b> entity.
|
||||
* Class holding properties associated with the <b>sys:referenceable</b> aspect.
|
||||
* This aspect is common enough to warrant direct inclusion on the <b>Node</b> entity.
|
||||
*
|
||||
* @author Derek Hulley
|
||||
* @since 3.4
|
||||
@@ -86,8 +87,10 @@ public class ReferenceablePropertiesEntity
|
||||
/**
|
||||
* Adds all {@link ContentModel#ASPECT_REFERENCEABLE referencable} properties.
|
||||
*/
|
||||
public static void addReferenceableProperties(Long nodeId, NodeRef nodeRef, Map<QName, Serializable> properties)
|
||||
public static void addReferenceableProperties(Node node, Map<QName, Serializable> properties)
|
||||
{
|
||||
Long nodeId = node.getId();
|
||||
NodeRef nodeRef = node.getNodeRef();
|
||||
properties.put(ContentModel.PROP_STORE_PROTOCOL, nodeRef.getStoreRef().getProtocol());
|
||||
properties.put(ContentModel.PROP_STORE_IDENTIFIER, nodeRef.getStoreRef().getIdentifier());
|
||||
properties.put(ContentModel.PROP_NODE_UUID, nodeRef.getId());
|
||||
|
||||
@@ -116,7 +116,7 @@ public class NodeDAOImpl extends AbstractNodeDAOImpl
|
||||
private static final String SELECT_NODE_MAX_ID = "alfresco.node.select_NodeMaxId";
|
||||
private static final String SELECT_NODE_INTERVAL_BY_TYPE = "alfresco.node.select_MinMaxNodeIdForNodeType";
|
||||
private static final String SELECT_NODES_WITH_ASPECT_IDS = "alfresco.node.select_NodesWithAspectIds";
|
||||
private static final String SELECT_NODES_WITH_ASPECT_IDS_LIMITED = "alfresco.node.select.select_NodesWithAspectIds_Limited";
|
||||
private static final String SELECT_NODES_WITH_ASPECT_IDS_LIMITED = "alfresco.node.select_NodesWithAspectIds_Limited";
|
||||
private static final String INSERT_NODE_ASSOC = "alfresco.node.insert.insert_NodeAssoc";
|
||||
private static final String UPDATE_NODE_ASSOC = "alfresco.node.update_NodeAssoc";
|
||||
private static final String DELETE_NODE_ASSOC = "alfresco.node.delete_NodeAssoc";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 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
|
||||
@@ -39,10 +39,8 @@ import org.alfresco.service.namespace.QName;
|
||||
/**
|
||||
* Encapsulates events occurred in a single transaction.
|
||||
*
|
||||
* @param <REF>
|
||||
* entity (e.g. node, child association, peer association) reference type
|
||||
* @param <RES>
|
||||
* entity resource type
|
||||
* @param <REF> entity (e.g. node, child association, peer association) reference type
|
||||
* @param <RES> entity resource type
|
||||
*/
|
||||
public abstract class EventConsolidator<REF extends EntityRef, RES extends Resource>
|
||||
{
|
||||
@@ -92,31 +90,23 @@ public abstract class EventConsolidator<REF extends EntityRef, RES extends Resou
|
||||
/**
|
||||
* Builds and returns the {@link RepoEvent} instance.
|
||||
*
|
||||
* @param eventInfo
|
||||
* the object holding the event information
|
||||
* @param eventInfo the object holding the event information
|
||||
* @return the {@link RepoEvent} instance
|
||||
*/
|
||||
public RepoEvent<DataAttributes<RES>> getRepoEvent(EventInfo eventInfo)
|
||||
{
|
||||
final RepoEvent.Builder<DataAttributes<RES>> builder = RepoEvent.builder();
|
||||
|
||||
configureRepoEventBuilder(builder, eventInfo);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
protected void configureRepoEventBuilder(RepoEvent.Builder<DataAttributes<RES>> builder, EventInfo eventInfo)
|
||||
{
|
||||
EventType eventType = getDerivedEvent();
|
||||
|
||||
DataAttributes<RES> eventData = buildEventData(eventInfo, resource, eventType);
|
||||
|
||||
builder.setId(eventInfo.getId())
|
||||
return RepoEvent.<DataAttributes<RES>>builder()
|
||||
.setId(eventInfo.getId())
|
||||
.setSource(eventInfo.getSource())
|
||||
.setTime(eventInfo.getTimestamp())
|
||||
.setType(eventType.getType())
|
||||
.setData(eventData)
|
||||
.setDataschema(EventJSONSchema.getSchemaV1(eventType));
|
||||
.setDataschema(EventJSONSchema.getSchemaV1(eventType))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +114,7 @@ public abstract class EventConsolidator<REF extends EntityRef, RES extends Resou
|
||||
*/
|
||||
protected DataAttributes<RES> buildEventData(EventInfo eventInfo, RES resource, EventType eventType)
|
||||
{
|
||||
return EventData.<RES> builder()
|
||||
return EventData.<RES>builder()
|
||||
.setEventGroupId(eventInfo.getTxnId())
|
||||
.setResource(resource)
|
||||
.build();
|
||||
|
||||
@@ -542,7 +542,10 @@ public class EventGenerator extends AbstractLifecycleBean implements Initializin
|
||||
@Override
|
||||
protected void onShutdown(ApplicationEvent applicationEvent)
|
||||
{
|
||||
// NOOP
|
||||
if (eventSender != null)
|
||||
{
|
||||
eventSender.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
protected class EventTransactionListener extends TransactionListenerAdapter
|
||||
|
||||
@@ -52,7 +52,7 @@ public interface EventSender
|
||||
}
|
||||
|
||||
/**
|
||||
* It's called when the bean instance is destroyed, allowing to perform cleanup operations.
|
||||
* It's called when the application context is closing, allowing {@link org.alfresco.repo.event2.EventGenerator} to perform cleanup operations.
|
||||
*/
|
||||
default void destroy()
|
||||
{
|
||||
|
||||
@@ -25,16 +25,15 @@
|
||||
*/
|
||||
package org.alfresco.repo.event2;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executor;
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.beans.factory.config.AbstractFactoryBean;
|
||||
import org.springframework.core.env.PropertyResolver;
|
||||
|
||||
import org.alfresco.util.PropertyCheck;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class EventSenderFactoryBean extends AbstractFactoryBean<EventSender>
|
||||
{
|
||||
@@ -156,13 +155,4 @@ public class EventSenderFactoryBean extends AbstractFactoryBean<EventSender>
|
||||
{
|
||||
return event2MessageProducer;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void destroyInstance(EventSender eventSender)
|
||||
{
|
||||
if (eventSender != null)
|
||||
{
|
||||
eventSender.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -125,9 +125,6 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
||||
/** Number of (bytecode) instructions that will trigger the observer */
|
||||
private int observerInstructionCount = 100;
|
||||
|
||||
/** Flag to enable or disable scope cleaning at the end of each script execution */
|
||||
private boolean cleanScope = true;
|
||||
|
||||
/** Custom context factory */
|
||||
public static AlfrescoContextFactory contextFactory;
|
||||
|
||||
@@ -211,15 +208,6 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
||||
this.observerInstructionCount = observerInstructionCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cleanScope
|
||||
* true to enable scope cleaning at the end of each script execution - set to false to disable this feature.
|
||||
*/
|
||||
public void setCleanScope(boolean cleanScope)
|
||||
{
|
||||
this.cleanScope = cleanScope;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.alfresco.service.cmr.repository.ScriptProcessor#reset()
|
||||
*/
|
||||
@@ -626,7 +614,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!secure && cleanScope)
|
||||
if (!secure)
|
||||
{
|
||||
unsetScope(model, scope);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Repository
|
||||
* %%
|
||||
* Copyright (C) 2005 - 2025 Alfresco Software Limited
|
||||
* Copyright (C) 2005 - 2016 Alfresco Software Limited
|
||||
* %%
|
||||
* This file is part of the Alfresco software.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
@@ -40,10 +40,6 @@ import java.util.ResourceBundle.Control;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
import org.alfresco.model.ContentModel;
|
||||
import org.alfresco.query.CannedQueryFactory;
|
||||
import org.alfresco.query.CannedQueryResults;
|
||||
@@ -98,6 +94,9 @@ import org.alfresco.util.Pair;
|
||||
import org.alfresco.util.ParameterCheck;
|
||||
import org.alfresco.util.SearchLanguageConversion;
|
||||
import org.alfresco.util.registry.NamedObjectRegistry;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.extensions.surf.util.I18NUtil;
|
||||
|
||||
/**
|
||||
* Implementation of the file/folder-specific service.
|
||||
@@ -109,27 +108,31 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
private static final String CANNED_QUERY_FILEFOLDER_LIST = "fileFolderGetChildrenCannedQueryFactory";
|
||||
|
||||
/** Shallow search for files and folders with a name pattern */
|
||||
private static final String XPATH_QUERY_SHALLOW_ALL = "./*" +
|
||||
private static final String XPATH_QUERY_SHALLOW_ALL =
|
||||
"./*" +
|
||||
"[like(@cm:name, $cm:name, false)" +
|
||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "')" +
|
||||
" or subtypeOf('" + ContentModel.TYPE_LINK + "'))]";
|
||||
|
||||
/** Deep search for files and folders with a name pattern */
|
||||
private static final String XPATH_QUERY_DEEP_ALL = ".//*" +
|
||||
private static final String XPATH_QUERY_DEEP_ALL =
|
||||
".//*" +
|
||||
"[like(@cm:name, $cm:name, false)" +
|
||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "') or subtypeOf('" + ContentModel.TYPE_CONTENT + "')" +
|
||||
" or subtypeOf('" + ContentModel.TYPE_LINK + "'))]";
|
||||
|
||||
/** Deep search for folders with a name pattern */
|
||||
private static final String XPATH_QUERY_DEEP_FOLDERS = ".//*" +
|
||||
private static final String XPATH_QUERY_DEEP_FOLDERS =
|
||||
".//*" +
|
||||
"[like(@cm:name, $cm:name, false)" +
|
||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_FOLDER + "'))]";
|
||||
|
||||
/** Deep search for files with a name pattern */
|
||||
private static final String XPATH_QUERY_DEEP_FILES = ".//*" +
|
||||
private static final String XPATH_QUERY_DEEP_FILES =
|
||||
".//*" +
|
||||
"[like(@cm:name, $cm:name, false)" +
|
||||
" and not (subtypeOf('" + ContentModel.TYPE_SYSTEM_FOLDER + "'))" +
|
||||
" and (subtypeOf('" + ContentModel.TYPE_CONTENT + "')" +
|
||||
@@ -165,7 +168,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
{
|
||||
super();
|
||||
|
||||
fileFolderTrait = new ExtendedTrait<FileFolderServiceTrait>(AJProxyTrait.create(createFileFolderTrait(), FileFolderServiceTrait.class));
|
||||
fileFolderTrait=new ExtendedTrait<FileFolderServiceTrait>(AJProxyTrait.create(createFileFolderTrait(),FileFolderServiceTrait.class));
|
||||
}
|
||||
|
||||
public void setNamespaceService(NamespaceService namespaceService)
|
||||
@@ -242,17 +245,17 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
return preserveAuditableData;
|
||||
}
|
||||
|
||||
|
||||
public void init()
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to convert node reference instances to file info
|
||||
*
|
||||
* @param nodeRefs
|
||||
* the node references
|
||||
* @param nodeRefs the node references
|
||||
* @return Return a list of file info
|
||||
* @throws InvalidTypeException
|
||||
* if the node is not a valid type
|
||||
* @throws InvalidTypeException if the node is not a valid type
|
||||
*/
|
||||
private List<FileInfo> toFileInfo(List<NodeRef> nodeRefs) throws InvalidTypeException
|
||||
{
|
||||
@@ -266,7 +269,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
catch (InvalidNodeRefException inre)
|
||||
{
|
||||
logger.warn("toFileInfo: " + inre);
|
||||
logger.warn("toFileInfo: "+inre);
|
||||
// skip
|
||||
}
|
||||
}
|
||||
@@ -289,7 +292,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
boolean isHidden = false;
|
||||
|
||||
Client client = FileFilterMode.getClient();
|
||||
if (hiddenAspect.getVisibility(client, nodeRef) == Visibility.HiddenAttribute)
|
||||
if(hiddenAspect.getVisibility(client, nodeRef) == Visibility.HiddenAttribute)
|
||||
{
|
||||
isHidden = true;
|
||||
}
|
||||
@@ -366,7 +369,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
|
||||
@Override
|
||||
@Extend(traitAPI = FileFolderServiceTrait.class, extensionAPI = FileFolderServiceExtension.class)
|
||||
@Extend(traitAPI=FileFolderServiceTrait.class,extensionAPI=FileFolderServiceExtension.class)
|
||||
public List<FileInfo> list(NodeRef contextNodeRef)
|
||||
{
|
||||
// execute the query
|
||||
@@ -411,25 +414,23 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
PermissionCheckedCollectionMixin.create(nodeInfos, nodeRefs);
|
||||
|
||||
return new PagingResults<FileInfo>() {
|
||||
return new PagingResults<FileInfo>()
|
||||
{
|
||||
@Override
|
||||
public String getQueryExecutionId()
|
||||
{
|
||||
return results.getQueryExecutionId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> getPage()
|
||||
{
|
||||
return nodeInfos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreItems()
|
||||
{
|
||||
return results.hasMoreItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<Integer, Integer> getTotalResultCount()
|
||||
{
|
||||
@@ -439,8 +440,8 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
*
|
||||
* @see org.alfresco.service.cmr.model.FileFolderService#list(org.alfresco.service.cmr.repository.NodeRef, boolean, boolean, java.util.Set, org.alfresco.service.cmr.model.PagingSortRequest) */
|
||||
* @see org.alfresco.service.cmr.model.FileFolderService#list(org.alfresco.service.cmr.repository.NodeRef, boolean, boolean, java.util.Set, org.alfresco.service.cmr.model.PagingSortRequest)
|
||||
*/
|
||||
@Auditable(parameters = {"contextNodeRef", "files", "folders", "ignoreQNames", "sortProps", "pagingRequest"})
|
||||
@Override
|
||||
@Extend(traitAPI = FileFolderServiceTrait.class, extensionAPI = FileFolderServiceExtension.class)
|
||||
@@ -454,7 +455,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
ParameterCheck.mandatory("contextNodeRef", contextNodeRef);
|
||||
ParameterCheck.mandatory("pagingRequest", pagingRequest);
|
||||
|
||||
Pair<Set<QName>, Set<QName>> pair = buildSearchTypesAndIgnoreAspects(files, folders, ignoreQNames);
|
||||
Pair<Set<QName>,Set<QName>> pair = buildSearchTypesAndIgnoreAspects(files, folders, ignoreQNames);
|
||||
Set<QName> searchTypeQNames = pair.getFirst();
|
||||
Set<QName> ignoreAspectQNames = pair.getSecond();
|
||||
|
||||
@@ -464,13 +465,13 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
|
||||
@Override
|
||||
@Extend(traitAPI = FileFolderServiceTrait.class, extensionAPI = FileFolderServiceExtension.class)
|
||||
@Extend(traitAPI=FileFolderServiceTrait.class,extensionAPI=FileFolderServiceExtension.class)
|
||||
public PagingResults<FileInfo> list(NodeRef contextNodeRef, boolean files, boolean folders, String pattern, Set<QName> ignoreQNames, List<Pair<QName, Boolean>> sortProps, PagingRequest pagingRequest)
|
||||
{
|
||||
ParameterCheck.mandatory("contextNodeRef", contextNodeRef);
|
||||
ParameterCheck.mandatory("pagingRequest", pagingRequest);
|
||||
|
||||
Pair<Set<QName>, Set<QName>> pair = buildSearchTypesAndIgnoreAspects(files, folders, ignoreQNames);
|
||||
Pair<Set<QName>,Set<QName>> pair = buildSearchTypesAndIgnoreAspects(files, folders, ignoreQNames);
|
||||
Set<QName> searchTypeQNames = pair.getFirst();
|
||||
Set<QName> ignoreAspectQNames = pair.getSecond();
|
||||
|
||||
@@ -479,8 +480,9 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
return getPagingResults(pagingRequest, results);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Extend(traitAPI = FileFolderServiceTrait.class, extensionAPI = FileFolderServiceExtension.class)
|
||||
@Extend(traitAPI=FileFolderServiceTrait.class,extensionAPI=FileFolderServiceExtension.class)
|
||||
public PagingResults<FileInfo> list(NodeRef rootNodeRef, Set<QName> searchTypeQNames, Set<QName> ignoreAspectQNames, List<Pair<QName, Boolean>> sortProps, PagingRequest pagingRequest)
|
||||
{
|
||||
CannedQueryResults<NodeRef> results = listImpl(rootNodeRef, null, searchTypeQNames, ignoreAspectQNames, sortProps, pagingRequest);
|
||||
@@ -534,9 +536,9 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
Long start = (logger.isDebugEnabled() ? System.currentTimeMillis() : null);
|
||||
|
||||
// get canned query
|
||||
GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory) cannedQueryRegistry.getNamedObject(CANNED_QUERY_FILEFOLDER_LIST);
|
||||
GetChildrenCannedQueryFactory getChildrenCannedQueryFactory = (GetChildrenCannedQueryFactory)cannedQueryRegistry.getNamedObject(CANNED_QUERY_FILEFOLDER_LIST);
|
||||
|
||||
GetChildrenCannedQuery cq = (GetChildrenCannedQuery) getChildrenCannedQueryFactory.getCannedQuery(contextNodeRef, pattern, assocTypeQNames, searchTypeQNames, ignoreAspectQNames, filterProps, sortProps, pagingRequest);
|
||||
GetChildrenCannedQuery cq = (GetChildrenCannedQuery)getChildrenCannedQueryFactory.getCannedQuery(contextNodeRef, pattern, assocTypeQNames, searchTypeQNames, ignoreAspectQNames, filterProps, sortProps, pagingRequest);
|
||||
|
||||
// execute canned query
|
||||
CannedQueryResults<NodeRef> results = cq.execute();
|
||||
@@ -550,7 +552,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
Pair<Integer, Integer> totalCount = (pagingRequest.getRequestTotalCountMax() > 0 ? results.getTotalResultCount() : null);
|
||||
int pageNum = (skipCount / maxItems) + 1;
|
||||
|
||||
logger.debug("List: " + cnt + " items in " + (System.currentTimeMillis() - start) + " msecs [pageNum=" + pageNum + ",skip=" + skipCount + ",max=" + maxItems + ",hasMorePages=" + hasMoreItems + ",totalCount=" + totalCount + ",parentNodeRef=" + contextNodeRef + "]");
|
||||
logger.debug("List: "+cnt+" items in "+(System.currentTimeMillis()-start)+" msecs [pageNum="+pageNum+",skip="+skipCount+",max="+maxItems+",hasMorePages="+hasMoreItems+",totalCount="+totalCount+",parentNodeRef="+contextNodeRef+"]");
|
||||
}
|
||||
|
||||
return results;
|
||||
@@ -657,7 +659,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
* @see #search(NodeRef, String, boolean, boolean, boolean)
|
||||
*/
|
||||
@Override
|
||||
@Extend(traitAPI = FileFolderServiceTrait.class, extensionAPI = FileFolderServiceExtension.class)
|
||||
@Extend(traitAPI=FileFolderServiceTrait.class,extensionAPI=FileFolderServiceExtension.class)
|
||||
public List<FileInfo> search(NodeRef contextNodeRef, String namePattern, boolean includeSubFolders)
|
||||
{
|
||||
return search(contextNodeRef, namePattern, true, true, includeSubFolders);
|
||||
@@ -669,7 +671,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
* Full search with all options
|
||||
*/
|
||||
@Override
|
||||
@Extend(traitAPI = FileFolderServiceTrait.class, extensionAPI = FileFolderServiceExtension.class)
|
||||
@Extend(traitAPI=FileFolderServiceTrait.class,extensionAPI=FileFolderServiceExtension.class)
|
||||
public List<FileInfo> search(
|
||||
NodeRef contextNodeRef,
|
||||
String namePattern,
|
||||
@@ -711,7 +713,9 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a full search, but doesn't translate the node references into file info objects. This allows {@link #checkExists(NodeRef, String)} to bypass the retrieval of node properties.
|
||||
* Performs a full search, but doesn't translate the node references into
|
||||
* file info objects. This allows {@link #checkExists(NodeRef, String)} to
|
||||
* bypass the retrieval of node properties.
|
||||
*/
|
||||
private List<NodeRef> searchInternal(
|
||||
NodeRef contextNodeRef,
|
||||
@@ -737,7 +741,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
if (anyName)
|
||||
{
|
||||
// This is search for any name
|
||||
if (includeSubFolders)
|
||||
if(includeSubFolders)
|
||||
{
|
||||
nodeRefs = listSimpleDeep(contextNodeRef, fileSearch, folderSearch, null);
|
||||
}
|
||||
@@ -771,12 +775,12 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
if (includeSubFolders)
|
||||
{
|
||||
// this is a deep search
|
||||
if (!fileSearch && folderSearch)
|
||||
if(!fileSearch && folderSearch)
|
||||
{
|
||||
// This is a folder search only;
|
||||
query = XPATH_QUERY_DEEP_FOLDERS;
|
||||
}
|
||||
else if (fileSearch && !folderSearch)
|
||||
else if(fileSearch && !folderSearch)
|
||||
{
|
||||
// This is a folder search only;
|
||||
query = XPATH_QUERY_DEEP_FILES;
|
||||
@@ -892,24 +896,27 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
|
||||
/**
|
||||
* A deep version of listSimple. Which recursively walks down the tree from a given starting point, returning the node refs of files or folders found along the way.
|
||||
* A deep version of listSimple. Which recursively walks down the tree from a given starting point, returning
|
||||
* the node refs of files or folders found along the way.
|
||||
* <p>
|
||||
* The folder filter is called for each sub-folder to determine whether to search in that sub-folder, should a subfolder be excluded then all its chidren are excluded as well.
|
||||
* The folder filter is called for each sub-folder to determine whether to search in that sub-folder, should a subfolder be excluded
|
||||
* then all its chidren are excluded as well.
|
||||
*
|
||||
* @param contextNodeRef
|
||||
* the starting point.
|
||||
* @param files
|
||||
* return nodes of type files.
|
||||
* @param folders
|
||||
* return nodes of type folders.
|
||||
* @param folderFilter
|
||||
* filter controls which folders to search. If null then all subfolders are searched.
|
||||
* @param contextNodeRef the starting point.
|
||||
* @param files return nodes of type files.
|
||||
* @param folders return nodes of type folders.
|
||||
* @param folderFilter filter controls which folders to search. If null then all subfolders are searched.
|
||||
* @return list of node references
|
||||
*/
|
||||
/* <p> MER: I've added this rather than changing listSimple to minimise the risk of breaking the existing code. This is a quick performance improvement between using XPath which is awful or adding new methods to the NodeService/DB This is also a dangerous method in that it can return a lot of data and take a long time. */
|
||||
/* <p>
|
||||
* MER: I've added this rather than changing listSimple to minimise the risk of breaking
|
||||
* the existing code. This is a quick performance improvement between using
|
||||
* XPath which is awful or adding new methods to the NodeService/DB This is also a dangerous method in that it can return a
|
||||
* lot of data and take a long time.
|
||||
*/
|
||||
private List<NodeRef> listSimpleDeep(NodeRef contextNodeRef, boolean files, boolean folders, SubFolderFilter folderFilter)
|
||||
{
|
||||
if (logger.isDebugEnabled())
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("searchSimpleDeep contextNodeRef:" + contextNodeRef);
|
||||
}
|
||||
@@ -921,7 +928,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
Set<QName> folderTypeQNames = buildFolderTypes();
|
||||
Set<QName> fileTypeQNames = (files ? buildFileTypes() : new HashSet<QName>(0));
|
||||
|
||||
if (!folders && !files)
|
||||
if(!folders && !files)
|
||||
{
|
||||
return Collections.emptyList();
|
||||
|
||||
@@ -937,7 +944,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
toSearch.push(contextNodeRef);
|
||||
|
||||
// Now we need to walk down the folders.
|
||||
while (!toSearch.empty())
|
||||
while(!toSearch.empty())
|
||||
{
|
||||
NodeRef currentDir = toSearch.pop();
|
||||
|
||||
@@ -947,10 +954,10 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
{
|
||||
// We have some child folders
|
||||
boolean include = true;
|
||||
if (folderFilter != null)
|
||||
if(folderFilter != null)
|
||||
{
|
||||
include = folderFilter.isEnterSubfolder(folderRef);
|
||||
if (include)
|
||||
if(include)
|
||||
{
|
||||
// yes search in these subfolders
|
||||
toSearch.push(folderRef.getChildRef());
|
||||
@@ -962,13 +969,13 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
toSearch.push(folderRef.getChildRef());
|
||||
}
|
||||
|
||||
if (folders && include)
|
||||
if(folders && include)
|
||||
{
|
||||
result.add(folderRef.getChildRef());
|
||||
}
|
||||
}
|
||||
|
||||
if (files)
|
||||
if(files)
|
||||
{
|
||||
// Add the files in the current dir
|
||||
List<ChildAssociationRef> fileAssocRefs = nodeService.getChildAssocs(currentDir, fileTypeQNames);
|
||||
@@ -979,7 +986,8 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled())
|
||||
|
||||
if(logger.isDebugEnabled())
|
||||
{
|
||||
logger.debug("searchSimpleDeep finished size:" + result.size());
|
||||
}
|
||||
@@ -992,7 +1000,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
* @see #move(NodeRef, NodeRef, String)
|
||||
*/
|
||||
@Override
|
||||
@Extend(traitAPI = FileFolderServiceTrait.class, extensionAPI = FileFolderServiceExtension.class)
|
||||
@Extend(traitAPI=FileFolderServiceTrait.class,extensionAPI=FileFolderServiceExtension.class)
|
||||
public FileInfo rename(NodeRef sourceNodeRef, String newName) throws FileExistsException, FileNotFoundException
|
||||
{
|
||||
return moveOrCopy(sourceNodeRef, null, null, newName, true);
|
||||
@@ -1037,8 +1045,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
/**
|
||||
* Implements both move and copy behaviour
|
||||
*
|
||||
* @param move
|
||||
* true to move, otherwise false to copy
|
||||
* @param move true to move, otherwise false to copy
|
||||
*/
|
||||
private FileInfo moveOrCopy(NodeRef sourceNodeRef, NodeRef sourceParentRef, NodeRef targetParentRef, String newName, boolean move) throws FileExistsException, FileNotFoundException
|
||||
{
|
||||
@@ -1190,7 +1197,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
|
||||
// Only update the name if it has changed
|
||||
String currentName = (String) nodeService.getProperty(targetNodeRef, ContentModel.PROP_NAME);
|
||||
String currentName = (String)nodeService.getProperty(targetNodeRef, ContentModel.PROP_NAME);
|
||||
|
||||
// ALF-13949: WorkingCopyAspect intentionally generates new names for all copies of working copies (which no
|
||||
// longer have the working copy aspect) so leave these alone after copy
|
||||
@@ -1202,7 +1209,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
nodeService.setProperty(targetNodeRef, ContentModel.PROP_NAME, newName);
|
||||
|
||||
// May need to update the mimetype, to support apps using .tmp files when saving
|
||||
ContentData contentData = (ContentData) nodeService.getProperty(targetNodeRef, ContentModel.PROP_CONTENT);
|
||||
ContentData contentData = (ContentData)nodeService.getProperty(targetNodeRef, ContentModel.PROP_CONTENT);
|
||||
|
||||
// Check the newName and oldName extensions.
|
||||
// Keep previous mimetype if
|
||||
@@ -1252,8 +1259,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
*
|
||||
* TODO: Replace this with a more formal means of identifying "system" folders (i.e. aspect or UUID)
|
||||
*
|
||||
* @param nodeRef
|
||||
* node to check
|
||||
* @param nodeRef node to check
|
||||
* @return true => system folder path based node
|
||||
*/
|
||||
private boolean isSystemPath(NodeRef nodeRef)
|
||||
@@ -1314,7 +1320,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
catch (DuplicateChildNodeNameException e)
|
||||
{
|
||||
throw new FileExistsException(parentNodeRef, name, typeQName.getLocalName());
|
||||
throw new FileExistsException(parentNodeRef, name);
|
||||
}
|
||||
|
||||
NodeRef nodeRef = assocRef.getChildRef();
|
||||
@@ -1345,14 +1351,12 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
/**
|
||||
* Checks for the presence of, and creates as necessary, the folder structure in the provided path.
|
||||
* <p>
|
||||
* An empty path list is not allowed as it would be impossible to necessarily return file info for the parent node - it might not be a folder node.
|
||||
*
|
||||
* @param parentNodeRef
|
||||
* the node under which the path will be created
|
||||
* @param pathElements
|
||||
* the folder name path to create - may not be empty
|
||||
* @param folderTypeQName
|
||||
* the types of nodes to create. This must be a valid subtype of {@link org.alfresco.model.ContentModel#TYPE_FOLDER they folder type}.
|
||||
* An empty path list is not allowed as it would be impossible to necessarily return file info
|
||||
* for the parent node - it might not be a folder node.
|
||||
* @param parentNodeRef the node under which the path will be created
|
||||
* @param pathElements the folder name path to create - may not be empty
|
||||
* @param folderTypeQName the types of nodes to create. This must be a valid subtype of
|
||||
* {@link org.alfresco.model.ContentModel#TYPE_FOLDER they folder type}.
|
||||
* @return Returns the info of the last folder in the path.
|
||||
* @deprecated Use FileFolderUtil.makeFolders rather than directly accessing this implementation class.
|
||||
*/
|
||||
@@ -1364,14 +1368,12 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
/**
|
||||
* Checks for the presence of, and creates as necessary, the folder structure in the provided path.
|
||||
* <p>
|
||||
* An empty path list is not allowed as it would be impossible to necessarily return file info for the parent node - it might not be a folder node.
|
||||
*
|
||||
* @param parentNodeRef
|
||||
* the node under which the path will be created
|
||||
* @param pathElements
|
||||
* the folder name path to create - may not be empty
|
||||
* @param folderTypeQName
|
||||
* the types of nodes to create. This must be a valid subtype of {@link org.alfresco.model.ContentModel#TYPE_FOLDER they folder type}.
|
||||
* An empty path list is not allowed as it would be impossible to necessarily return file info
|
||||
* for the parent node - it might not be a folder node.
|
||||
* @param parentNodeRef the node under which the path will be created
|
||||
* @param pathElements the folder name path to create - may not be empty
|
||||
* @param folderTypeQName the types of nodes to create. This must be a valid subtype of
|
||||
* {@link org.alfresco.model.ContentModel#TYPE_FOLDER they folder type}.
|
||||
* @return Returns the info of the last folder in the path.
|
||||
* @deprecated Use FileFolderUtil.makeFolders rather than directly accessing this implementation class.
|
||||
*/
|
||||
@@ -1384,17 +1386,17 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
* Get the file or folder information from the root down to and including the node provided.
|
||||
* <ul>
|
||||
* <li>The root node can be of any type and is not included in the path list.</li>
|
||||
* <li>Only the primary path is considered. If the target node is not a descendant of the root along purely primary associations, then an exception is generated.</li>
|
||||
* <li>Only the primary path is considered. If the target node is not a descendant of the
|
||||
* root along purely primary associations, then an exception is generated.</li>
|
||||
* <li>If an invalid type is encountered along the path, then an exception is generated.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param rootNodeRef
|
||||
* the start of the returned path, or null if the <b>store</b> root node must be assumed.
|
||||
* @param nodeRef
|
||||
* a reference to the file or folder
|
||||
* @return Returns a list of file/folder infos from the root (excluded) down to and including the destination file or folder
|
||||
* @throws FileNotFoundException
|
||||
* if the node could not be found
|
||||
* @param rootNodeRef the start of the returned path, or null if the <b>store</b> root
|
||||
* node must be assumed.
|
||||
* @param nodeRef a reference to the file or folder
|
||||
* @return Returns a list of file/folder infos from the root (excluded) down to and
|
||||
* including the destination file or folder
|
||||
* @throws FileNotFoundException if the node could not be found
|
||||
*/
|
||||
@Override
|
||||
public List<FileInfo> getNamePath(NodeRef rootNodeRef, NodeRef nodeRef) throws FileNotFoundException
|
||||
@@ -1429,7 +1431,8 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
}
|
||||
// we found the root and expect to be building the path up
|
||||
// Run as system as the user could not have access to all folders in the path, see ALF-13816
|
||||
FileInfo pathInfo = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<FileInfo>() {
|
||||
FileInfo pathInfo = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<FileInfo>()
|
||||
{
|
||||
public FileInfo doWork() throws Exception
|
||||
{
|
||||
return toFileInfo(childNodeRef, true);
|
||||
@@ -1438,7 +1441,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
|
||||
// we can't append a path element to the results if there is already a (non-folder) file at the tail
|
||||
// since this would result in a path anomoly - file's cannot contain other files.
|
||||
if (!results.isEmpty() && !results.get(results.size() - 1).isFolder())
|
||||
if (!results.isEmpty() && !results.get(results.size()-1).isFolder())
|
||||
{
|
||||
throw new InvalidTypeException(
|
||||
"File is not the last element in path: files cannot contain other files.");
|
||||
@@ -1470,17 +1473,17 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
* Get the file or folder names from the root down to and including the node provided.
|
||||
* <ul>
|
||||
* <li>The root node can be of any type and is not included in the path list.</li>
|
||||
* <li>Only the primary path is considered. If the target node is not a descendant of the root along purely primary associations, then an exception is generated.</li>
|
||||
* <li>Only the primary path is considered. If the target node is not a descendant of the
|
||||
* root along purely primary associations, then an exception is generated.</li>
|
||||
* <li>If an invalid type is encountered along the path, then an exception is generated.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param rootNodeRef
|
||||
* the start of the returned path, or null if the <b>store</b> root node must be assumed.
|
||||
* @param nodeRef
|
||||
* a reference to the file or folder
|
||||
* @return Returns a list of file/folder names from the root (excluded) down to and including the destination file or folder
|
||||
* @throws FileNotFoundException
|
||||
* if the node could not be found
|
||||
* @param rootNodeRef the start of the returned path, or null if the <b>store</b> root
|
||||
* node must be assumed.
|
||||
* @param nodeRef a reference to the file or folder
|
||||
* @return Returns a list of file/folder names from the root (excluded) down to and
|
||||
* including the destination file or folder
|
||||
* @throws FileNotFoundException if the node could not be found
|
||||
*/
|
||||
@Override
|
||||
public List<String> getNameOnlyPath(NodeRef rootNodeRef, final NodeRef nodeRef) throws FileNotFoundException
|
||||
@@ -1495,7 +1498,8 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
final NodeRef rNodeRef = rootNodeRef;
|
||||
final ArrayList<String> results = new ArrayList<String>(10);
|
||||
// Run as system as the user could not have access to all folders in the path, see ALF-13816
|
||||
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Void>() {
|
||||
AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork<Void>()
|
||||
{
|
||||
public Void doWork() throws Exception
|
||||
{
|
||||
// get the primary path
|
||||
@@ -1548,10 +1552,9 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
// the runAs() is too keen on wrapping everything in an outer RuntimeException - which we don't want.
|
||||
if (e.getCause() instanceof FileNotFoundException)
|
||||
{
|
||||
throw (FileNotFoundException) e.getCause();
|
||||
throw (FileNotFoundException)e.getCause();
|
||||
}
|
||||
else
|
||||
throw e;
|
||||
else throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1690,8 +1693,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
Visibility webDavVisibility = isHidden ? Visibility.NotVisible : Visibility.Visible;
|
||||
for (Client client : hiddenAspect.getClients())
|
||||
{
|
||||
Visibility clientVisibility = client == FileFilterMode.getClient() ? webDavVisibility
|
||||
: hiddenAspect
|
||||
Visibility clientVisibility = client == FileFilterMode.getClient() ? webDavVisibility : hiddenAspect
|
||||
.getVisibility(client, nodeRef);
|
||||
if (clientVisibility != Visibility.Visible)
|
||||
{
|
||||
@@ -1813,6 +1815,7 @@ public class FileFolderServiceImpl extends AbstractBaseCopyService implements Fi
|
||||
|
||||
}
|
||||
|
||||
|
||||
public PagingResults<FileInfo> list(NodeRef contextNodeRef,
|
||||
boolean files,
|
||||
boolean folders,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user