Compare commits

..

26 Commits

Author SHA1 Message Date
alfresco-build
187646895c [maven-release-plugin][skip ci] prepare release 23.6.0.21 2025-09-22 12:43:22 +00:00
Tiago Salvado
f9515e336f [ACS-10166] Include qname and namespace in NodeIdsWhichReferenceContentUrl query (#3579) (#3582) 2025-09-22 12:57:36 +01:00
alfresco-build
828dd20576 [maven-release-plugin][skip ci] prepare for next development iteration 2025-09-22 09:21:07 +00:00
alfresco-build
3372e20c35 [maven-release-plugin][skip ci] prepare release 23.6.0.20 2025-09-22 09:21:05 +00:00
Gerard Olenski
64b5cace27 ACS-10159 Bump ATS (#3581) 2025-09-22 10:12:37 +02:00
alfresco-build
83acf26cf4 [maven-release-plugin][skip ci] prepare for next development iteration 2025-09-18 11:13:01 +00:00
alfresco-build
b3be0f2b7f [maven-release-plugin][skip ci] prepare release 23.6.0.19 2025-09-18 11:12:59 +00:00
Belal Ansari
7a6ebb9a05 Backporting MNT-25216 Error on fixedAclUpdaterJobDetail execution when using Oracle to ACS 23 (#3575) 2025-09-18 15:57:15 +05:30
alfresco-build
fa0f239618 [maven-release-plugin][skip ci] prepare for next development iteration 2025-09-17 01:05:50 +00:00
alfresco-build
43799408a8 [maven-release-plugin][skip ci] prepare release 23.6.0.18 2025-09-17 01:05:48 +00:00
Tiago Salvado
e7305006f0 [ACS-9929] Bump cxf version to 4.1.2 (#3572) 2025-09-17 01:21:54 +01:00
alfresco-build
40c30411af [maven-release-plugin][skip ci] prepare for next development iteration 2025-09-12 11:02:12 +00:00
alfresco-build
91f8b43237 [maven-release-plugin][skip ci] prepare release 23.6.0.17 2025-09-12 11:02:09 +00:00
Eva Vasques
6fccf828e1 ACS-10042 - AGS Concurrent IPR Group Creation (#3566) (#3570) 2025-09-12 11:10:43 +01:00
alfresco-build
3fac3373c9 [maven-release-plugin][skip ci] prepare for next development iteration 2025-09-04 08:24:19 +00:00
alfresco-build
ee857ce1de [maven-release-plugin][skip ci] prepare release 23.6.0.16 2025-09-04 08:24:17 +00:00
Debjit Chattopadhyay
483d7fab21 Merge pull request #3563 from Alfresco/fix/MNT-24776-backport-23.N
backport MNT-24776 to 23.N
2025-09-04 13:01:59 +05:30
Debjit Chattopadhyay
590209b299 Fix for "MNT-24776 : Category Picker Error when a User does not have Read Permissions to a Category"
(cherry picked from commit 626640ddc7)
2025-09-03 15:14:48 +05:30
alfresco-build
376514df67 [maven-release-plugin][skip ci] prepare for next development iteration 2025-08-29 13:30:01 +00:00
alfresco-build
7144a2dd94 [maven-release-plugin][skip ci] prepare release 23.6.0.15 2025-08-29 13:29:59 +00:00
Debjit Chattopadhyay
b4da3d8c20 MNT-24308 - fix search filterquery creation for displaying favourites in Share for both Solr and Elasticsearch
MNT-24308 : On click of 'My Favorites' link under 'Documents' in the left panel of 'Document Library' page, all the links appear grayed out
2025-08-29 18:15:59 +05:30
Debjit Chattopadhyay
62de9ff0c0 MNT-24308 : On click of 'My Favorites' link under 'Documents' in the left panel of 'Document Library' page, all the links appear grayed out 2025-08-29 16:25:23 +05:30
alfresco-build
a11acce720 [maven-release-plugin][skip ci] prepare for next development iteration 2025-08-28 13:37:40 +00:00
alfresco-build
1128011e15 [maven-release-plugin][skip ci] prepare release 23.6.0.14 2025-08-28 13:37:38 +00:00
Tiago Salvado
d0cb45de0d [MNT-25242] Add property to control if scope is cleaned (#3520) (#3550) 2025-08-28 11:18:05 +01:00
alfresco-build
2b48195896 [maven-release-plugin][skip ci] prepare for next development iteration 2025-08-28 10:12:53 +00:00
38 changed files with 501 additions and 169 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,6 +15,13 @@
<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"/>
@@ -55,18 +62,21 @@
<!-- Get list of node ids which reference given content url -->
<select id="select_NodeIdsWhichReferenceContentUrl"
parameterType="ContentUrl"
parameterMap="parameter_NodeIdsWhichReferenceContentUrl"
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)
WHERE
content_url_short = #{contentUrlShort} and
content_url_crc = #{contentUrlCrc}
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 = ?
</select>
<select id="select_RecordFoldersWithSchedules"

View File

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

View File

@@ -27,7 +27,6 @@
package org.alfresco.module.org_alfresco_module_rm.query;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -36,6 +35,11 @@ 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;
@@ -47,9 +51,6 @@ 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
@@ -89,7 +90,8 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
protected TenantService tenantService;
/**
* @param sqlSessionTemplate SQL session template
* @param sqlSessionTemplate
* SQL session template
*/
public final void setSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate)
{
@@ -97,7 +99,8 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
}
/**
* @param qnameDAO qname DAO
* @param qnameDAO
* qname DAO
*/
public final void setQnameDAO(QNameDAO qnameDAO)
{
@@ -173,8 +176,9 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
/**
* Get a set of node reference which reference the provided content URL
*
* @param String contentUrl content URL
* @return Set<NodeRef> set of nodes that reference the provided content URL
* @param String
* contentUrl content URL
* @return Set<NodeRef> set of nodes that reference the provided content URL
*/
@Override
public Set<NodeRef> getNodeRefsWhichReferenceContentUrl(String contentUrl)
@@ -188,13 +192,19 @@ 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, contentUrlEntity);
List<Long> nodeIds = template.selectList(SELECT_NODE_IDS_WHICH_REFERENCE_CONTENT_URL, params);
if (logger.isDebugEnabled())
{
@@ -224,7 +234,7 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
if (logger.isDebugEnabled())
{
logMessage.append(nodeRefToAdd)
.append(" (from version)");
.append(" (from version)");
}
}
@@ -232,7 +242,7 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
else
{
nodeRefToAdd = nodeDAO.getNodeIdStatus(nodeId)
.getNodeRef();
.getNodeRef();
if (logger.isDebugEnabled())
{
logMessage.append(nodeRefToAdd);
@@ -266,9 +276,9 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
{
Map<String, Object> params = new HashMap<>(2);
params.put("processed", qnameDAO.getQName(ASPECT_DISPOSITION_PROCESSED)
.getFirst());
.getFirst());
params.put("folderQnameId", qnameDAO.getQName(TYPE_RECORD_FOLDER)
.getFirst());
.getFirst());
params.put("start", start);
params.put("end", end);
@@ -280,7 +290,7 @@ public class RecordsManagementQueryDAOImpl implements RecordsManagementQueryDAO,
for (NodeRefEntity nodeRefEntity : entities)
{
results.add(
new NodeRef(nodeRefEntity.getProtocol(), nodeRefEntity.getIdentifier(), nodeRefEntity.getUuid()));
new NodeRef(nodeRefEntity.getProtocol(), nodeRefEntity.getIdentifier(), nodeRefEntity.getUuid()));
}
return results;
@@ -289,7 +299,8 @@ 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);

View File

@@ -36,6 +36,7 @@ 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;
@@ -649,8 +650,8 @@ public class ExtendedSecurityServiceImpl extends ServiceBaseImpl
}
catch (DuplicateChildNodeNameException ex)
{
// the group was concurrently created
group = authorityService.getName(AuthorityType.GROUP, groupShortName);
// 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);
}
return group;

View File

@@ -29,14 +29,23 @@ 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;
@@ -73,8 +82,7 @@ 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();
@@ -90,8 +98,7 @@ 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));
@@ -118,7 +125,7 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
// test remove
extendedSecurityService.remove(recordToo);
assertFalse(extendedSecurityService.hasExtendedSecurity(recordToo));
assertTrue(extendedSecurityService.getReaders(recordToo).isEmpty());
assertTrue(extendedSecurityService.getWriters(recordToo).isEmpty());
@@ -133,8 +140,7 @@ 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
@@ -184,112 +190,337 @@ public class ExtendedSecurityServiceImplTest extends BaseRMTestCase
public void testDifferentUsersDifferentPermissions()
{
final String userNone = createTestUser();
final String userRead = createTestUser();
final String userWrite = createTestUser();
final String siteShortName = GUID.generate();
final String userNone = createTestUser();
final String userRead = createTestUser();
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);
return null;
siteService.createSite(null, siteShortName, "test", "test", SiteVisibility.PRIVATE);
return null;
}
});
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);
siteService.setMembership(siteShortName, userWrite, SiteModel.SITE_COLLABORATOR);
return siteService.createContainer(siteShortName, SiteService.DOCUMENT_LIBRARY, null, null);
siteService.setMembership(siteShortName, userRead, SiteModel.SITE_CONSUMER);
siteService.setMembership(siteShortName, userWrite, SiteModel.SITE_COLLABORATOR);
return siteService.createContainer(siteShortName, SiteService.DOCUMENT_LIBRARY, null, null);
}
});
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();
recordService.createRecord(filePlan, record);
return record;
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>()
{
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, FILING));
return null;
}
}, userNone);
AuthenticationUtil.runAs(new RunAsWork<Void>() {
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, FILING));
return null;
}
}, userNone);
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, FILING));
return null;
}
}, userRead);
AuthenticationUtil.runAs(new RunAsWork<Void>() {
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, FILING));
return null;
}
}, userRead);
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, FILING));
return null;
}
}, userWrite);
AuthenticationUtil.runAs(new RunAsWork<Void>() {
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, FILING));
return null;
}
}, userWrite);
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, FILING));
return null;
}
}, userNone);
AuthenticationUtil.runAs(new RunAsWork<Void>() {
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, FILING));
return null;
}
}, userNone);
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, FILING));
return null;
}
}, userRead);
AuthenticationUtil.runAs(new RunAsWork<Void>() {
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(record, FILING));
return null;
}
}, userRead);
AuthenticationUtil.runAs(new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, FILING));
return null;
}
}, userWrite);
AuthenticationUtil.runAs(new RunAsWork<Void>() {
public Void doWork() throws Exception
{
// check permissions
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, READ_RECORDS));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(record, FILING));
return null;
}
}, userWrite);
return null;
return null;
}
});
}
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);
}
}
}

View File

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

View File

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

View File

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

View File

@@ -91,6 +91,15 @@ 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
*
@@ -123,6 +132,28 @@ 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

View File

@@ -182,11 +182,14 @@ var Filters =
case "favourites":
for (var favourite in favourites)
{
if (filterQuery)
if (favourite && favourite.trim() !== "")
{
filterQuery += " OR ";
if (filterQuery)
{
filterQuery += " OR ";
}
filterQuery += "ID:\"" + favourite + "\"";
}
filterQuery += "ID:\"" + favourite + "\"";
}
if (filterQuery.length !== 0)
@@ -201,7 +204,13 @@ var Filters =
else
{
// empty favourites query
filterQuery = "+ID:\"\"";
logger.warn("No favourites found for user: " + person.properties.userName);
return {
query: null,
limitResults: 0,
sort: [],
language: "lucene"
};
}
filterParams.query = filterQuery;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,7 +8,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-tests</artifactId>
<version>23.6.0.13</version>
<version>23.6.0.21</version>
</parent>
<properties>

View File

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

View File

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

10
pom.xml
View File

@@ -2,7 +2,7 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>alfresco-community-repo</artifactId>
<version>23.6.0.13</version>
<version>23.6.0.21</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -51,8 +51,8 @@
<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.1.5</dependency.alfresco-transform-core.version>
<dependency.alfresco-transform-service.version>4.1.5</dependency.alfresco-transform-service.version>
<dependency.alfresco-transform-core.version>5.2.2-A.1</dependency.alfresco-transform-core.version>
<dependency.alfresco-transform-service.version>4.2.2-A.1</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>
@@ -61,7 +61,7 @@
<dependency.spring-security.version>6.3.9</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.0</dependency.cxf.version>
<dependency.cxf.version>4.1.2</dependency.cxf.version>
<dependency.opencmis.version>1.0.0-jakarta-1</dependency.opencmis.version>
<dependency.webscripts.version>10.2</dependency.webscripts.version>
<dependency.bouncycastle.version>1.78.1</dependency.bouncycastle.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.6.0.13</tag>
<tag>23.6.0.21</tag>
</scm>
<distributionManagement>

View File

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

View File

@@ -40,6 +40,7 @@
"items":
[
<#list results as row>
<#if row.item.hasPermission("Read")>
{
"type": "${row.item.typeShort}",
"parentType": "${row.item.parentTypeShort!""}",
@@ -75,6 +76,7 @@
"nodeRef": "${row.item.nodeRef}"<#if row.selectable?exists>,
"selectable" : ${row.selectable?string}</#if>
}<#if row_has_next>,</#if>
</#if>
</#list>
]
}

View File

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

View File

@@ -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_NodesWithAspectIds_Limited";
private static final String SELECT_NODES_WITH_ASPECT_IDS_LIMITED = "alfresco.node.select.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";

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* 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
@@ -125,6 +125,9 @@ 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;
@@ -209,6 +212,15 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
}
/**
* @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()
*/
public void reset()
@@ -614,7 +626,7 @@ public class RhinoScriptProcessor extends BaseProcessor implements ScriptProcess
}
finally
{
if (!secure)
if (!secure && cleanScope)
{
unsetScope(model, scope);
}

View File

@@ -782,25 +782,6 @@
<if test="ordered == true">order by node.id ASC</if>
</select>
<select id="select_NodesWithAspectIds_Limited" parameterType="Ids" resultMap="result_NodeRef" >
select
node.id as id,
store.protocol as protocol,
store.identifier as identifier,
node.uuid as uuid
from
alf_node_aspects na
join alf_node node on (na.node_id = node.id)
left join alf_store store on (store.id = node.store_id)
where
<![CDATA[na.node_id >= #{idOne}]]>
<if test="idTwo != null"><![CDATA[and na.node_id < #{idTwo}]]></if>
and na.qname_id in
<foreach item="item" index="i" collection="ids" open="(" separator="," close=")">#{item}</foreach>
<if test="ordered == true">order by node.id ASC</if>
<if test="maxResults != null"><![CDATA[limit #{maxResults}]]></if>
</select>
<!-- Common results for result_NodeAssoc -->
<sql id="select_NodeAssoc_Results">
select
@@ -1566,4 +1547,4 @@
</foreach>
</delete>
</mapper>
</mapper>

View File

@@ -30,4 +30,23 @@
<![CDATA[and commit_time_ms <= #{maxCommitTime}]]>
</select>
</mapper>
<select id="select_NodesWithAspectIds_Limited" parameterType="Ids" resultMap="alfresco.node.result_NodeRef" >
select
node.id as id,
store.protocol as protocol,
store.identifier as identifier,
node.uuid as uuid
from
alf_node_aspects na
join alf_node node on (na.node_id = node.id)
left join alf_store store on (store.id = node.store_id)
where
<![CDATA[na.node_id >= #{idOne}]]>
<if test="idTwo != null"><![CDATA[and na.node_id < #{idTwo}]]></if>
and na.qname_id in
<foreach item="item" index="i" collection="ids" open="(" separator="," close=")">#{item}</foreach>
<if test="ordered == true">order by node.id ASC</if>
<if test="maxResults != null"><![CDATA[limit #{maxResults}]]></if>
</select>
</mapper>

View File

@@ -30,4 +30,23 @@
<![CDATA[and commit_time_ms <= #{maxCommitTime}]]>
</select>
</mapper>
<select id="select_NodesWithAspectIds_Limited" parameterType="Ids" resultMap="alfresco.node.result_NodeRef" >
select
node.id as id,
store.protocol as protocol,
store.identifier as identifier,
node.uuid as uuid
from
alf_node_aspects na
join alf_node node on (na.node_id = node.id)
left join alf_store store on (store.id = node.store_id)
where
<![CDATA[na.node_id >= #{idOne}]]>
<if test="idTwo != null"><![CDATA[and na.node_id < #{idTwo}]]></if>
and na.qname_id in
<foreach item="item" index="i" collection="ids" open="(" separator="," close=")">#{item}</foreach>
<if test="ordered == true">order by node.id ASC</if>
<if test="maxResults != null"><![CDATA[limit #{maxResults}]]></if>
</select>
</mapper>

View File

@@ -1394,6 +1394,9 @@ scripts.execution.maxMemoryUsedInBytes=-1
# Number of instructions that will trigger the observer
scripts.execution.observerInstructionCount=5000
# Flag to control if the scope is cleaned at the end of script execution
scripts.execution.clean.scope=true
# Default value being used in POST/size-details endpoint to partition a huge folder into smaller chunks
# so that we can compute more efficiently and consolidate all sizes into a single unit.
default.async.folder.items=1000

View File

@@ -60,6 +60,9 @@
<property name="observerInstructionCount">
<value>${scripts.execution.observerInstructionCount}</value>
</property>
<property name="cleanScope">
<value>${scripts.execution.clean.scope}</value>
</property>
</bean>
<!-- base config implementation that script extension beans extend from - for auto registration