mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-10-01 14:41:46 +00:00
MNT-20714: /nodes/{nodeId}/content REST API fails for content created by a deleted user
cherry-pick 3bf2a0ce73
from master
This commit is contained in:
@@ -2449,26 +2449,21 @@ public class NodesImpl implements Nodes
|
|||||||
@Override
|
@Override
|
||||||
public Node moveOrCopyNode(String sourceNodeId, String targetParentId, String name, Parameters parameters, boolean isCopy)
|
public Node moveOrCopyNode(String sourceNodeId, String targetParentId, String name, Parameters parameters, boolean isCopy)
|
||||||
{
|
{
|
||||||
FileInfo fi = retryingTransactionHelper.doInTransaction(() -> {
|
if ((sourceNodeId == null) || (sourceNodeId.isEmpty()))
|
||||||
if ((sourceNodeId == null) || (sourceNodeId.isEmpty()))
|
{
|
||||||
{
|
throw new InvalidArgumentException("Missing sourceNodeId");
|
||||||
throw new InvalidArgumentException("Missing sourceNodeId");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ((targetParentId == null) || (targetParentId.isEmpty()))
|
if ((targetParentId == null) || (targetParentId.isEmpty()))
|
||||||
{
|
{
|
||||||
throw new InvalidArgumentException("Missing targetParentId");
|
throw new InvalidArgumentException("Missing targetParentId");
|
||||||
}
|
}
|
||||||
|
|
||||||
final NodeRef parentNodeRef = validateOrLookupNode(targetParentId, null);
|
final NodeRef parentNodeRef = validateOrLookupNode(targetParentId, null);
|
||||||
final NodeRef sourceNodeRef = validateOrLookupNode(sourceNodeId, null);
|
final NodeRef sourceNodeRef = validateOrLookupNode(sourceNodeId, null);
|
||||||
|
|
||||||
return moveOrCopyImpl(sourceNodeRef, parentNodeRef, name, isCopy);
|
FileInfo fi = moveOrCopyImpl(sourceNodeRef, parentNodeRef, name, isCopy);
|
||||||
}, false, true);
|
return getFolderOrDocument(fi.getNodeRef().getId(), parameters);
|
||||||
|
|
||||||
return retryingTransactionHelper.doInTransaction(() -> {
|
|
||||||
return getFolderOrDocument(fi.getNodeRef().getId(), parameters);
|
|
||||||
}, false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateCustomAspects(NodeRef nodeRef, List<String> aspectNames, List<QName> excludedAspects)
|
public void updateCustomAspects(NodeRef nodeRef, List<String> aspectNames, List<QName> excludedAspects)
|
||||||
@@ -3271,28 +3266,22 @@ public class NodesImpl implements Nodes
|
|||||||
@Override
|
@Override
|
||||||
public Node lock(String nodeId, LockInfo lockInfo, Parameters parameters)
|
public Node lock(String nodeId, LockInfo lockInfo, Parameters parameters)
|
||||||
{
|
{
|
||||||
retryingTransactionHelper.doInTransaction(() -> {
|
NodeRef nodeRef = validateOrLookupNode(nodeId, null);
|
||||||
NodeRef nodeRef = validateOrLookupNode(nodeId, null);
|
|
||||||
|
|
||||||
if (isSpecialNode(nodeRef, getNodeType(nodeRef)))
|
if (isSpecialNode(nodeRef, getNodeType(nodeRef)))
|
||||||
{
|
{
|
||||||
throw new PermissionDeniedException("Current user doesn't have permission to lock node " + nodeId);
|
throw new PermissionDeniedException("Current user doesn't have permission to lock node " + nodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nodeMatches(nodeRef, Collections.singleton(ContentModel.TYPE_CONTENT), null, false))
|
if (!nodeMatches(nodeRef, Collections.singleton(ContentModel.TYPE_CONTENT), null, false))
|
||||||
{
|
{
|
||||||
throw new InvalidArgumentException("Node of type cm:content or a subtype is expected: " + nodeId);
|
throw new InvalidArgumentException("Node of type cm:content or a subtype is expected: " + nodeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
LockInfo validatedLockInfo = validateLockInformation(lockInfo);
|
LockInfo validatedLockInfo = validateLockInformation(lockInfo);
|
||||||
lockService.lock(nodeRef, validatedLockInfo.getMappedType(), validatedLockInfo.getTimeToExpire(), validatedLockInfo.getLifetime());
|
lockService.lock(nodeRef, validatedLockInfo.getMappedType(), validatedLockInfo.getTimeToExpire(), validatedLockInfo.getLifetime());
|
||||||
|
|
||||||
return null;
|
return getFolderOrDocument(nodeId, parameters);
|
||||||
}, false, true);
|
|
||||||
|
|
||||||
return retryingTransactionHelper.doInTransaction(() -> {
|
|
||||||
return getFolderOrDocument(nodeId, parameters);
|
|
||||||
}, false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LockInfo validateLockInformation(LockInfo lockInfo)
|
private LockInfo validateLockInformation(LockInfo lockInfo)
|
||||||
@@ -3316,25 +3305,19 @@ public class NodesImpl implements Nodes
|
|||||||
@Override
|
@Override
|
||||||
public Node unlock(String nodeId, Parameters parameters)
|
public Node unlock(String nodeId, Parameters parameters)
|
||||||
{
|
{
|
||||||
retryingTransactionHelper.doInTransaction(() -> {
|
NodeRef nodeRef = validateOrLookupNode(nodeId, null);
|
||||||
NodeRef nodeRef = validateOrLookupNode(nodeId, null);
|
|
||||||
|
|
||||||
if (isSpecialNode(nodeRef, getNodeType(nodeRef)))
|
if (isSpecialNode(nodeRef, getNodeType(nodeRef)))
|
||||||
{
|
{
|
||||||
throw new PermissionDeniedException("Current user doesn't have permission to unlock node " + nodeId);
|
throw new PermissionDeniedException("Current user doesn't have permission to unlock node " + nodeId);
|
||||||
}
|
}
|
||||||
if (!lockService.isLocked(nodeRef))
|
if (!lockService.isLocked(nodeRef))
|
||||||
{
|
{
|
||||||
throw new IntegrityException("Can't unlock node " + nodeId + " because it isn't locked", null);
|
throw new IntegrityException("Can't unlock node " + nodeId + " because it isn't locked", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
lockService.unlock(nodeRef);
|
lockService.unlock(nodeRef);
|
||||||
return null;
|
return getFolderOrDocument(nodeId, parameters);
|
||||||
}, false, true);
|
|
||||||
|
|
||||||
return retryingTransactionHelper.doInTransaction(() -> {
|
|
||||||
return getFolderOrDocument(nodeId, parameters);
|
|
||||||
}, false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -163,7 +163,7 @@ public class Node implements Comparable<Node>
|
|||||||
PersonService.PersonInfo pInfo = null;
|
PersonService.PersonInfo pInfo = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
NodeRef pNodeRef = personService.getPerson(userName, false);
|
NodeRef pNodeRef = personService.getPersonOrNull(userName);
|
||||||
if (pNodeRef != null)
|
if (pNodeRef != null)
|
||||||
{
|
{
|
||||||
pInfo = personService.getPerson(pNodeRef);
|
pInfo = personService.getPerson(pNodeRef);
|
||||||
|
@@ -4431,6 +4431,76 @@ public class NodeApiTest extends AbstractSingleNetworkSiteTest
|
|||||||
assertEquals(f1Id, documentResp.getParentId());
|
assertEquals(f1Id, documentResp.getParentId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests update of content after owner of the document is deleted
|
||||||
|
* <p>PUT:</p>
|
||||||
|
* {@literal <host>:<port>/alfresco/api/-default-/public/alfresco/versions/1/nodes/<nodeId>/content}
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testUploadContentDeletedOwner() throws Exception
|
||||||
|
{
|
||||||
|
// Create person2delete
|
||||||
|
String personToDelete = createUser("usertodelete-" + RUNID, "userdelPassword", networkOne);
|
||||||
|
|
||||||
|
// PersonToDelete creates a site and adds user1 as a site collab
|
||||||
|
setRequestContext(personToDelete);
|
||||||
|
String site1Title = "site-testUploadContentDeadUser_DocLib-" + RUNID;
|
||||||
|
String site1Id = createSite(site1Title, SiteVisibility.PUBLIC).getId();
|
||||||
|
String site1DocLibNodeId = getSiteContainerNodeId(site1Id, "documentLibrary");
|
||||||
|
|
||||||
|
addSiteMember(site1Id, user1, SiteRole.SiteCollaborator);
|
||||||
|
|
||||||
|
// PersonToDelete creates a file within DL
|
||||||
|
Document deadDoc = createTextFile(site1DocLibNodeId, "testdeaddoc.txt", "The quick brown fox jumps over the lazy dog 1.");
|
||||||
|
final String deadDocUrl = getNodeContentUrl(deadDoc.getId());
|
||||||
|
|
||||||
|
// PersonToDelete updates the file
|
||||||
|
String content = "Soft you a word or two before you go... I took by the throat the circumcised dog, And smote him, thus.";
|
||||||
|
String docName = "goodbye-world.txt";
|
||||||
|
Map params_doc = new HashMap<>();
|
||||||
|
params_doc.put(Nodes.PARAM_NAME, docName);
|
||||||
|
deadDoc = updateFileWithContent(deadDoc.getId(), content, params_doc, 200);
|
||||||
|
assertEquals("person2delete cannot update document", docName, deadDoc.getName());
|
||||||
|
|
||||||
|
// Download the file and confirm its contents on person2delete
|
||||||
|
HttpResponse response = getSingle(deadDocUrl, personToDelete, null, 200);
|
||||||
|
assertEquals("person2delete cannot view document", content, response.getResponse());
|
||||||
|
|
||||||
|
// Download the file and confirm its contents on user1
|
||||||
|
response = getSingle(deadDocUrl, user1, null, 200);
|
||||||
|
assertEquals("user1 cannot view document", content, response.getResponse());
|
||||||
|
|
||||||
|
// PersonToDelete is deleted
|
||||||
|
transactionHelper.doInTransaction(() -> {
|
||||||
|
deleteUser(personToDelete, networkOne);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// User1 updates the file
|
||||||
|
setRequestContext(user1);
|
||||||
|
content = "This did I fear, but thought he had no weapon; For he was great of heart.";
|
||||||
|
updateFileWithContent(deadDoc.getId(), content, null, 200);
|
||||||
|
|
||||||
|
// Download the file and confirm its contents (ensure rollback didn't happen)
|
||||||
|
response = getSingle(deadDocUrl, user1, null, 200);
|
||||||
|
assertEquals("user1 cannot update after owner is deleted", content, response.getResponse());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Document updateFileWithContent(String docId, String content, Map<String, String> params, int expectedStatus) throws Exception
|
||||||
|
{
|
||||||
|
ByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes());
|
||||||
|
File txtFile = TempFileProvider.createTempFile(inputStream, getClass().getSimpleName(), ".txt");
|
||||||
|
|
||||||
|
BinaryPayload payload = new BinaryPayload(txtFile);
|
||||||
|
|
||||||
|
HttpResponse response = putBinary(getNodeContentUrl(docId), payload, null, params, expectedStatus);
|
||||||
|
if (expectedStatus != 200)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return RestApiUtil.parseRestApiEntry(response.getJsonResponse(), Document.class);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates authority context
|
* Creates authority context
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user