Compare commits

...

30 Commits

Author SHA1 Message Date
Travis CI User
da6e87e001 [maven-release-plugin][skip ci] prepare release 12.9 2021-11-24 14:35:57 +00:00
tiagosalvado10
4197c29fce [MNT-21953] [MNT-22491] Clear rendition content data on content change. Prevent rendition from having contentHashCode without content (#752) (#819)
* [MNT-21953] [MNT-22491] Clear rendition content data on content change. Prevent rendition from having contentHashCode without content

* [MNT-21953] [MNT-22491] Added tests

* [MNT-21953] [MNT-22491] Removed update content from test

* [MNT-21953] [MNT-22491] Improve log messages

* [MNT-21953] [MNT-22491] Changed Copyright year to 2021. Minor change in test comments.

(cherry picked from commit 4314a30f3a)
2021-11-24 13:44:20 +00:00
Travis CI User
3d4785d5ae [maven-release-plugin][skip ci] prepare for next development iteration 2021-11-22 19:42:36 +00:00
Travis CI User
6c68658476 [maven-release-plugin][skip ci] prepare release 12.8 2021-11-22 19:42:33 +00:00
tiagosalvado10
1bd439e0ec [MNT-22680] Bump surf-webscripts to 8.26 (#814) (#815)
(cherry picked from commit 20a617adef)
2021-11-22 18:47:28 +00:00
Travis CI User
72f84ee50b [maven-release-plugin][skip ci] prepare for next development iteration 2021-11-22 14:15:06 +00:00
Travis CI User
50f26b9137 [maven-release-plugin][skip ci] prepare release 12.7 2021-11-22 14:15:02 +00:00
evasques
b6b1cc3ea0 MNT-18700 - Dynamic Message bundles do not deploy/reload automatically (#805) (#810)
* Restored the ability to register dynamic messages on bootstrap
* Added unit tests on bootstrap to verify if the dynamic messages are registered on bootstrap
* Added unit tests for the Repo Admin Console regarding registering dynamic messages and classpath files

(cherry picked from commit be4fa79c76)
2021-11-22 10:35:27 +00:00
Travis CI User
0f1c1cdba1 [maven-release-plugin][skip ci] prepare for next development iteration 2021-11-17 22:20:28 +00:00
Travis CI User
841bc6844e [maven-release-plugin][skip ci] prepare release 12.6 2021-11-17 22:20:25 +00:00
tiagosalvado10
a5bdf47f00 [PRODSEC-5795] Bump surf-webscripts to 8.25 (#803) (#804)
(cherry picked from commit ee07bb635f)
2021-11-17 21:28:16 +00:00
Travis CI User
a0b279d1ff [maven-release-plugin][skip ci] prepare for next development iteration 2021-10-25 14:21:26 +00:00
Travis CI User
fb967dfa9e [maven-release-plugin][skip ci] prepare release 12.5 2021-10-25 14:21:23 +00:00
Aleksandra Onych
f0a51e1347 MNT-21883 - Fix unshare content from smart folder (#765) (#772) 2021-10-25 15:00:23 +02:00
Travis CI User
42d56f9d20 [maven-release-plugin][skip ci] prepare for next development iteration 2021-10-19 11:04:24 +00:00
Travis CI User
3f31e4b1a2 [maven-release-plugin][skip ci] prepare release 12.4 2021-10-19 11:04:21 +00:00
Lev Belava
787a331869 MNT-21706 NodeService setAssociations list of elements is now handled. (#746) (#755)
MNT-21706 NodeService setAssociations list of elements is now handled.

(cherry picked from commit cbd45fcb3e)
2021-10-19 12:14:44 +02:00
Travis CI User
5ce3a3ddd6 [maven-release-plugin][skip ci] prepare for next development iteration 2021-10-06 11:41:46 +00:00
Travis CI User
9ed96ec593 [maven-release-plugin][skip ci] prepare release 12.3 2021-10-06 11:41:43 +00:00
montgolfiere
03b1fa8b09 ACS-2067: Fix probes for when DAU enabled (#700)
(cherry picked from commit 2ef97e0b23)
2021-10-06 11:38:04 +01:00
Travis CI User
d69f9b52c3 [maven-release-plugin][skip ci] prepare for next development iteration 2021-10-01 10:30:56 +00:00
Travis CI User
72b910bb48 [maven-release-plugin][skip ci] prepare release 12.2 2021-10-01 10:30:53 +00:00
evasques
cfaf3b280b MNT-22600 Nodes with security marks appear unfiltered on CMIS DB queries (#702) (#705)
* Change isUnfiltered to protected so we can extend it in enterprise
* Added test method to be able to do a cmis query test

Original commit in governance-services: e4e3235328

(cherry picked from commit c5281d7f10)
2021-10-01 10:18:01 +01:00
Travis CI User
00d814ec55 [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-29 13:39:07 +00:00
Travis CI User
becabb3a41 [maven-release-plugin][skip ci] prepare release 12.1 2021-09-29 13:39:04 +00:00
Piotr Żurek
033157800b MNT-22611 - Fix bulk import parameters parsing (#699)
Cherry-picked from 85a3c71849  master to 7.1.N (7.1.1)
2021-09-29 14:39:28 +02:00
Travis CI User
b9c8ff91e4 [maven-release-plugin][skip ci] prepare for next development iteration 2021-09-28 22:58:13 +00:00
Travis CI User
c54d46ab67 [maven-release-plugin][skip ci] prepare release 12.0 2021-09-28 22:58:10 +00:00
alandavis
dec514c5c2 Missing files from last commit 2021-09-28 23:07:16 +01:00
alandavis
7c5a8a1963 Get master ready for 7.1.1 development 2021-09-28 23:05:39 +01:00
50 changed files with 1832 additions and 689 deletions

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-amps</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<modules>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<modules>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>

View File

@@ -619,11 +619,27 @@ public class BaseRMRestTest extends RestTest
* @return
*/
public List<String> searchForContentAsUser(UserModel user, String term)
{
String query = "cm:name:*" + term + "*";
return searchForContentAsUser(user,query,"afts");
}
/**
* Returns search results for the given search term
*
* @param user
* @param term
* @param query language
* @return
* @throws Exception
*/
public List<String> searchForContentAsUser(UserModel user, String q, String queryLanguage)
{
getRestAPIFactory().getRmRestWrapper().authenticateUser(user);
RestRequestQueryModel queryReq = new RestRequestQueryModel();
SearchRequest query = new SearchRequest(queryReq);
queryReq.setQuery("cm:name:*" + term + "*");
queryReq.setQuery(q);
queryReq.setLanguage(queryLanguage);
List<String> names = new ArrayList<>();
// wait for solr indexing

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-governance-services-community-parent</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<modules>

View File

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

View File

@@ -306,7 +306,7 @@ public class RMAfterInvocationProvider extends RMSecurityCommon
}
}
private boolean isUnfiltered(NodeRef nodeRef)
protected boolean isUnfiltered(NodeRef nodeRef)
{
return !nodeService.hasAspect(nodeRef, RecordsManagementModel.ASPECT_FILE_PLAN_COMPONENT);

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<modules>

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<dependencies>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<properties>

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<properties>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<modules>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo-packaging</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<properties>

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>11.141-SNAPSHOT</version>
<version>12.9</version>
<packaging>pom</packaging>
<name>Alfresco Community Repo Parent</name>
@@ -24,7 +24,7 @@
<properties>
<acs.version.major>7</acs.version.major>
<acs.version.minor>1</acs.version.minor>
<acs.version.revision>0</acs.version.revision>
<acs.version.revision>1</acs.version.revision>
<acs.version.label />
<amp.min.version>${acs.version.major}.0.0</amp.min.version>
@@ -61,7 +61,7 @@
<dependency.jackson-databind.version>2.12.4</dependency.jackson-databind.version>
<dependency.cxf.version>3.4.4</dependency.cxf.version>
<dependency.opencmis.version>1.0.0</dependency.opencmis.version>
<dependency.webscripts.version>8.23</dependency.webscripts.version>
<dependency.webscripts.version>8.26</dependency.webscripts.version>
<dependency.bouncycastle.version>1.69</dependency.bouncycastle.version>
<dependency.mockito-core.version>3.11.2</dependency.mockito-core.version>
<dependency.mockito-all.version>1.10.19</dependency.mockito-all.version>
@@ -142,7 +142,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>HEAD</tag>
<tag>12.9</tag>
</scm>
<distributionManagement>

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<dependencies>

View File

@@ -30,8 +30,19 @@ import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.OptionalInt;
import java.util.function.Function;
import java.util.function.Supplier;
import com.google.common.primitives.Ints;
import org.alfresco.repo.bulkimport.BulkFilesystemImporter;
import org.alfresco.repo.bulkimport.BulkImportParameters;
import org.alfresco.repo.bulkimport.NodeImporter;
import org.alfresco.repo.bulkimport.impl.MultiThreadedBulkFilesystemImporter;
import org.alfresco.repo.model.Repository;
import org.alfresco.service.cmr.model.FileFolderService;
import org.alfresco.service.cmr.model.FileInfo;
@@ -39,8 +50,12 @@ import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.DeclarativeWebScript;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
import org.springframework.extensions.webscripts.WebScriptRequest;
/**
* contains common fields and methods for the import web scripts.
@@ -60,10 +75,10 @@ public class AbstractBulkFileSystemImportWebScript extends DeclarativeWebScript
// Web scripts parameters (common)
protected static final String PARAMETER_REPLACE_EXISTING = "replaceExisting";
protected static final String PARAMETER_EXISTING_FILE_MODE = "existingFileMode";
protected static final String PARAMETER_VALUE_REPLACE_EXISTING = "replaceExisting";
protected static final String PARAMETER_VALUE_REPLACE_EXISTING = "true";
protected static final String PARAMETER_SOURCE_DIRECTORY = "sourceDirectory";
protected static final String PARAMETER_DISABLE_RULES = "disableRules";
protected static final String PARAMETER_VALUE_DISABLE_RULES = "disableRules";
protected static final String PARAMETER_VALUE_DISABLE_RULES = "true";
protected static final String IMPORT_ALREADY_IN_PROGRESS_MODEL_KEY = "importInProgress";
protected static final String IMPORT_ALREADY_IN_PROGRESS_ERROR_KEY ="bfsit.error.importAlreadyInProgress";
@@ -75,7 +90,7 @@ public class AbstractBulkFileSystemImportWebScript extends DeclarativeWebScript
protected Repository repository;
protected volatile boolean importInProgress;
protected NodeRef getTargetNodeRef(String targetNodeRefStr, String targetPath) throws FileNotFoundException
{
NodeRef targetNodeRef;
@@ -219,4 +234,198 @@ public class AbstractBulkFileSystemImportWebScript extends DeclarativeWebScript
this.repository = repository;
}
protected class MultithreadedImportWebScriptLogic
{
private final MultiThreadedBulkFilesystemImporter bulkImporter;
private final Supplier<NodeImporter> nodeImporterFactory;
private final WebScriptRequest request;
private final Status status;
private final Cache cache;
public MultithreadedImportWebScriptLogic(MultiThreadedBulkFilesystemImporter bulkImporter, Supplier<NodeImporter> nodeImporterFactory, WebScriptRequest request, Status status, Cache cache)
{
this.bulkImporter = Objects.requireNonNull(bulkImporter);
this.nodeImporterFactory = Objects.requireNonNull(nodeImporterFactory);
this.request = Objects.requireNonNull(request);
this.status = Objects.requireNonNull(status);
this.cache = Objects.requireNonNull(cache);
}
public Map<String, Object> executeImport()
{
Map<String, Object> model = new HashMap<>();
cache.setNeverCache(true);
String targetPath = null;
try
{
targetPath = request.getParameter(PARAMETER_TARGET_PATH);
if (isRunning())
{
model.put(IMPORT_ALREADY_IN_PROGRESS_MODEL_KEY, I18NUtil.getMessage(IMPORT_ALREADY_IN_PROGRESS_ERROR_KEY));
return model;
}
final BulkImportParameters bulkImportParameters = getBulkImportParameters();
final NodeImporter nodeImporter = nodeImporterFactory.get();
bulkImporter.asyncBulkImport(bulkImportParameters, nodeImporter);
waitForImportToBegin();
// redirect to the status Web Script
status.setCode(Status.STATUS_MOVED_TEMPORARILY);
status.setRedirect(true);
status.setLocation(request.getServiceContextPath() + WEB_SCRIPT_URI_BULK_FILESYSTEM_IMPORT_STATUS);
}
catch (WebScriptException | IllegalArgumentException e)
{
status.setCode(Status.STATUS_BAD_REQUEST, e.getMessage());
status.setRedirect(true);
}
catch (FileNotFoundException fnfe)
{
status.setCode(Status.STATUS_BAD_REQUEST,"The repository path '" + targetPath + "' does not exist !");
status.setRedirect(true);
}
catch (Throwable t)
{
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, buildTextMessage(t), t);
}
return model;
}
private void waitForImportToBegin() throws InterruptedException
{
// ACE-3047 fix, since bulk import is started asynchronously there is a chance that client
// will get into the status page before import is actually started.
// In this case wrong information (for previous import) will be displayed.
// So lets ensure that import started before redirecting client to status page.
int i = 0;
while (!bulkImporter.getStatus().inProgress() && i < 10)
{
Thread.sleep(100);
i++;
}
}
private BulkImportParameters getBulkImportParameters() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = new BulkImportParametersExtractor(request::getParameter,
AbstractBulkFileSystemImportWebScript.this::getTargetNodeRef,
bulkImporter.getDefaultBatchSize(),
bulkImporter.getDefaultNumThreads());
return extractor.extract();
}
private boolean isRunning()
{
return bulkImporter.getStatus().inProgress();
}
}
protected static class BulkImportParametersExtractor
{
private final Function<String, String> paramsProvider;
private final NodeRefCreator nodeRefCreator;
private final int defaultBatchSize;
private final int defaultNumThreads;
public BulkImportParametersExtractor(final Function<String, String> paramsProvider, final NodeRefCreator nodeRefCreator,
final int defaultBatchSize, final int defaultNumThreads)
{
this.paramsProvider = Objects.requireNonNull(paramsProvider);
this.nodeRefCreator = Objects.requireNonNull(nodeRefCreator);
this.defaultBatchSize = defaultBatchSize;
this.defaultNumThreads = defaultNumThreads;
}
public BulkImportParameters extract() throws FileNotFoundException
{
BulkImportParameters result = new BulkImportParameters();
result.setTarget(getTargetNodeRef());
setExistingFileMode(result);
result.setNumThreads(getOptionalPositiveInteger(PARAMETER_NUM_THREADS).orElse(defaultNumThreads));
result.setBatchSize(getOptionalPositiveInteger(PARAMETER_BATCH_SIZE).orElse(defaultBatchSize));
setDisableRules(result);
return result;
}
private void setExistingFileMode(BulkImportParameters params)
{
String replaceExistingStr = getParamStringValue(PARAMETER_REPLACE_EXISTING);
String existingFileModeStr = getParamStringValue(PARAMETER_EXISTING_FILE_MODE);
if (!isNullOrEmpty(replaceExistingStr) && !isNullOrEmpty(existingFileModeStr))
{
// Check that we haven't had both the deprecated and new (existingFileMode)
// parameters supplied.
throw new IllegalStateException(
String.format("Only one of these parameters may be used, not both: %s, %s",
PARAMETER_REPLACE_EXISTING,
PARAMETER_EXISTING_FILE_MODE));
}
if (!isNullOrEmpty(existingFileModeStr))
{
params.setExistingFileMode(BulkImportParameters.ExistingFileMode.valueOf(existingFileModeStr));
}
else
{
params.setReplaceExisting(PARAMETER_VALUE_REPLACE_EXISTING.equals(replaceExistingStr));
}
}
private void setDisableRules(final BulkImportParameters params)
{
final String disableRulesStr = getParamStringValue(PARAMETER_DISABLE_RULES);
params.setDisableRulesService(!isNullOrEmpty(disableRulesStr) && PARAMETER_VALUE_DISABLE_RULES.equals(disableRulesStr));
}
private NodeRef getTargetNodeRef() throws FileNotFoundException
{
String targetNodeRefStr = getParamStringValue(PARAMETER_TARGET_NODEREF);
String targetPath = getParamStringValue(PARAMETER_TARGET_PATH);
return nodeRefCreator.fromNodeRefAndPath(targetNodeRefStr, targetPath);
}
private OptionalInt getOptionalPositiveInteger(final String paramName)
{
final String strValue = getParamStringValue(paramName);
if (isNullOrEmpty(strValue))
{
return OptionalInt.empty();
}
final Integer asInt = Ints.tryParse(strValue);
if (asInt == null || asInt < 1)
{
throw new WebScriptException("Error: parameter '" + paramName + "' must be an integer > 0.");
}
return OptionalInt.of(asInt);
}
private String getParamStringValue(String paramName)
{
Objects.requireNonNull(paramName);
return paramsProvider.apply(paramName);
}
private boolean isNullOrEmpty(String str)
{
return str == null || str.trim().length() == 0;
}
@FunctionalInterface
protected interface NodeRefCreator
{
NodeRef fromNodeRefAndPath(String nodeRef, String path) throws FileNotFoundException;
}
}
}

View File

@@ -27,17 +27,12 @@
package org.alfresco.repo.web.scripts.bulkimport.copy;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import org.alfresco.repo.bulkimport.BulkImportParameters;
import org.alfresco.repo.bulkimport.NodeImporter;
import org.alfresco.repo.bulkimport.impl.MultiThreadedBulkFilesystemImporter;
import org.alfresco.repo.bulkimport.impl.StreamingNodeImporterFactory;
import org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.springframework.extensions.surf.util.I18NUtil;
import org.springframework.extensions.webscripts.Cache;
import org.springframework.extensions.webscripts.Status;
import org.springframework.extensions.webscripts.WebScriptException;
@@ -69,170 +64,22 @@ public class BulkFilesystemImportWebScript extends AbstractBulkFileSystemImportW
@Override
protected Map<String, Object> executeImpl(final WebScriptRequest request, final Status status, final Cache cache)
{
Map<String, Object> model = new HashMap<String, Object>();
String targetNodeRefStr = null;
String targetPath = null;
String sourceDirectoryStr = null;
@Deprecated String replaceExistingStr = null;
String existingFileModeStr = null;
String batchSizeStr = null;
String numThreadsStr = null;
String disableRulesStr = null;
final MultithreadedImportWebScriptLogic importLogic = new MultithreadedImportWebScriptLogic(bulkImporter,
() -> createNodeImporter(request), request, status, cache);
return importLogic.executeImport();
}
cache.setNeverCache(true);
try
private NodeImporter createNodeImporter(WebScriptRequest request)
{
final String sourceDirectoryStr = request.getParameter(PARAMETER_SOURCE_DIRECTORY);
if (sourceDirectoryStr == null || sourceDirectoryStr.trim().length() == 0)
{
if(!bulkImporter.getStatus().inProgress())
{
NodeRef targetNodeRef = null;
File sourceDirectory = null;
boolean replaceExisting = false;
BulkImportParameters.ExistingFileMode existingFileMode = null;
int batchSize = bulkImporter.getDefaultBatchSize();
int numThreads = bulkImporter.getDefaultNumThreads();
boolean disableRules = false;
// Retrieve, validate and convert parameters
targetNodeRefStr = request.getParameter(PARAMETER_TARGET_NODEREF);
targetPath = request.getParameter(PARAMETER_TARGET_PATH);
sourceDirectoryStr = request.getParameter(PARAMETER_SOURCE_DIRECTORY);
replaceExistingStr = request.getParameter(PARAMETER_REPLACE_EXISTING);
existingFileModeStr = request.getParameter(PARAMETER_EXISTING_FILE_MODE);
batchSizeStr = request.getParameter(PARAMETER_BATCH_SIZE);
numThreadsStr = request.getParameter(PARAMETER_NUM_THREADS);
disableRulesStr = request.getParameter(PARAMETER_DISABLE_RULES);
targetNodeRef = getTargetNodeRef(targetNodeRefStr, targetPath);
if (sourceDirectoryStr == null || sourceDirectoryStr.trim().length() == 0)
{
throw new RuntimeException("Error: mandatory parameter '" + PARAMETER_SOURCE_DIRECTORY + "' was not provided.");
}
sourceDirectory = new File(sourceDirectoryStr.trim());
if (replaceExistingStr != null && existingFileModeStr != null)
{
// Check that we haven't had both the deprecated and new (existingFileMode)
// parameters supplied.
throw new IllegalStateException(
String.format("Only one of these parameters may be used, not both: %s, %s",
PARAMETER_REPLACE_EXISTING,
PARAMETER_EXISTING_FILE_MODE));
}
if (replaceExistingStr != null && replaceExistingStr.trim().length() > 0)
{
replaceExisting = PARAMETER_VALUE_REPLACE_EXISTING.equals(replaceExistingStr);
}
if (existingFileModeStr != null && existingFileModeStr.trim().length() > 0)
{
existingFileMode = BulkImportParameters.ExistingFileMode.valueOf(existingFileModeStr);
}
if (disableRulesStr != null && disableRulesStr.trim().length() > 0)
{
disableRules = PARAMETER_VALUE_DISABLE_RULES.equals(disableRulesStr);
}
// Initiate the import
NodeImporter nodeImporter = nodeImporterFactory.getNodeImporter(sourceDirectory);
BulkImportParameters bulkImportParameters = new BulkImportParameters();
if (numThreadsStr != null && numThreadsStr.trim().length() > 0)
{
try
{
numThreads = Integer.parseInt(numThreadsStr);
if(numThreads < 1)
{
throw new RuntimeException("Error: parameter '" + PARAMETER_NUM_THREADS + "' must be an integer > 0.");
}
bulkImportParameters.setNumThreads(numThreads);
}
catch(NumberFormatException e)
{
throw new RuntimeException("Error: parameter '" + PARAMETER_NUM_THREADS + "' must be an integer > 0.");
}
}
if (batchSizeStr != null && batchSizeStr.trim().length() > 0)
{
try
{
batchSize = Integer.parseInt(batchSizeStr);
if(batchSize < 1)
{
throw new RuntimeException("Error: parameter '" + PARAMETER_BATCH_SIZE + "' must be an integer > 0.");
}
bulkImportParameters.setBatchSize(batchSize);
}
catch(NumberFormatException e)
{
throw new RuntimeException("Error: parameter '" + PARAMETER_BATCH_SIZE + "' must be an integer > 0.");
}
}
if (existingFileMode != null)
{
bulkImportParameters.setExistingFileMode(existingFileMode);
}
else
{
// Fall back to the old/deprecated way.
bulkImportParameters.setReplaceExisting(replaceExisting);
}
bulkImportParameters.setTarget(targetNodeRef);
bulkImportParameters.setDisableRulesService(disableRules);
bulkImporter.asyncBulkImport(bulkImportParameters, nodeImporter);
// ACE-3047 fix, since bulk import is started asynchronously there is a chance that client
// will get into the status page before import is actually started.
// In this case wrong information (for previous import) will be displayed.
// So lets ensure that import started before redirecting client to status page.
int i = 0;
while (!bulkImporter.getStatus().inProgress() && i < 10)
{
Thread.sleep(100);
i++;
}
// redirect to the status Web Script
status.setCode(Status.STATUS_MOVED_TEMPORARILY);
status.setRedirect(true);
status.setLocation(request.getServiceContextPath() + WEB_SCRIPT_URI_BULK_FILESYSTEM_IMPORT_STATUS);
}
else
{
model.put(IMPORT_ALREADY_IN_PROGRESS_MODEL_KEY, I18NUtil.getMessage(IMPORT_ALREADY_IN_PROGRESS_ERROR_KEY));
}
throw new WebScriptException("Error: mandatory parameter '" + PARAMETER_SOURCE_DIRECTORY + "' was not provided.");
}
catch (WebScriptException wse)
{
status.setCode(Status.STATUS_BAD_REQUEST, wse.getMessage());
status.setRedirect(true);
}
catch (FileNotFoundException fnfe)
{
status.setCode(Status.STATUS_BAD_REQUEST,"The repository path '" + targetPath + "' does not exist !");
status.setRedirect(true);
}
catch(IllegalArgumentException iae)
{
status.setCode(Status.STATUS_BAD_REQUEST,iae.getMessage());
status.setRedirect(true);
}
catch (Throwable t)
{
throw new WebScriptException(Status.STATUS_INTERNAL_SERVER_ERROR, buildTextMessage(t), t);
}
return model;
final File sourceDirectory = new File(sourceDirectoryStr.trim());
return nodeImporterFactory.getNodeImporter(sourceDirectory);
}
}

View File

@@ -1,28 +1,28 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.quickshare;
import java.util.HashMap;
@@ -31,10 +31,12 @@ import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.alfresco.model.QuickShareModel;
import org.alfresco.repo.tenant.TenantUtil;
import org.alfresco.service.cmr.quickshare.InvalidSharedIdException;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.webscripts.Cache;
@@ -82,14 +84,15 @@ public class UnshareContentDelete extends AbstractQuickShareContent
try
{
NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond();
Pair<String, NodeRef> pair = quickShareService.getTenantNodeRefFromSharedId(sharedId);
String networkTenantDomain = pair.getFirst();
String sharedBy = (String) nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
if (!quickShareService.canDeleteSharedLink(nodeRef, sharedBy))
TenantUtil.runAsSystemTenant(() ->
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Can't perform unshare action: " + sharedId);
}
quickShareService.unshareContent(sharedId);
checkIfCanDeleteSharedLink(sharedId);
quickShareService.unshareContent(sharedId);
return null;
}, networkTenantDomain);
Map<String, Object> model = new HashMap<>(1);
model.put("success", Boolean.TRUE);
@@ -106,4 +109,14 @@ public class UnshareContentDelete extends AbstractQuickShareContent
throw new WebScriptException(HttpServletResponse.SC_NOT_FOUND, "Unable to find: " + sharedId);
}
}
private void checkIfCanDeleteSharedLink(String sharedId) {
NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond();
String sharedBy = (String) nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
if (!quickShareService.canDeleteSharedLink(nodeRef, sharedBy))
{
throw new WebScriptException(HttpServletResponse.SC_FORBIDDEN, "Can't perform unshare action: " + sharedId);
}
}
}

View File

@@ -274,15 +274,15 @@ public class QuickShareLinksImpl implements QuickShareLinks, RecognizedParamsExt
try
{
NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond();
Pair<String, NodeRef> pair = quickShareService.getTenantNodeRefFromSharedId(sharedId);
String networkTenantDomain = pair.getFirst();
String sharedByUserId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
if (!quickShareService.canDeleteSharedLink(nodeRef, sharedByUserId))
TenantUtil.runAsSystemTenant(() ->
{
throw new PermissionDeniedException("Can't perform unshare action: " + sharedId);
}
quickShareService.unshareContent(sharedId);
checkIfCanDeleteSharedLink(sharedId);
quickShareService.unshareContent(sharedId);
return null;
}, networkTenantDomain);
}
catch (InvalidSharedIdException ex)
{
@@ -698,4 +698,14 @@ public class QuickShareLinksImpl implements QuickShareLinks, RecognizedParamsExt
throw new InvalidArgumentException("A valid recipientEmail must be specified.");
}
}
private void checkIfCanDeleteSharedLink(String sharedId) {
NodeRef nodeRef = quickShareService.getTenantNodeRefFromSharedId(sharedId).getSecond();
String sharedByUserId = (String)nodeService.getProperty(nodeRef, QuickShareModel.PROP_QSHARE_SHAREDBY);
if (!quickShareService.canDeleteSharedLink(nodeRef, sharedByUserId))
{
throw new PermissionDeniedException("Can't perform unshare action: " + sharedId);
}
}
}

View File

@@ -1070,7 +1070,7 @@
<property name="enabled" value="${system.api.discovery.enabled}" />
<property name="thumbnailService" ref="ThumbnailService" />
<property name="restApiDirectUrlConfig" ref="restApiDirectUrlConfig" />
<property name="contentService" ref="ContentService" />
<property name="contentService" ref="contentService" />
</bean>
<bean id="org.alfresco.rest.api.probes.ProbeEntityResource.get" class="org.alfresco.rest.api.probes.ProbeEntityResource">

View File

@@ -42,6 +42,7 @@ import org.junit.runners.Suite;
org.alfresco.rest.api.tests.TestPublicApiAtomPub10TCK.class,
org.alfresco.rest.api.tests.TestPublicApiAtomPub11TCK.class,
org.alfresco.rest.api.tests.TestPublicApiBrowser11TCK.class,
org.alfresco.repo.web.scripts.bulkimport.BulkImportParametersExtractorTest.class
})
public class AppContext01TestSuite
{

View File

@@ -0,0 +1,252 @@
/*
* #%L
* Alfresco Remote API
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.web.scripts.bulkimport;
import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_BATCH_SIZE;
import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_DISABLE_RULES;
import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_NUM_THREADS;
import static org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.PARAMETER_TARGET_NODEREF;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Map;
import org.alfresco.repo.bulkimport.BulkImportParameters;
import org.alfresco.repo.bulkimport.BulkImportParameters.ExistingFileMode;
import org.alfresco.repo.web.scripts.bulkimport.AbstractBulkFileSystemImportWebScript.BulkImportParametersExtractor;
import org.alfresco.service.cmr.model.FileNotFoundException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.junit.Test;
import org.springframework.extensions.webscripts.WebScriptException;
public class BulkImportParametersExtractorTest
{
private static final String TEST_NODE_REF = "workspace://SpacesStore/this-is-just-a-test-ref";
private static final String TEST_MISSING_NODE_REF = "workspace://SpacesStore/this-is-just-a-not-existing-test-ref";
private static final Integer DEFAULT_BATCH_SIZE = 1234;
private static final Integer DEFAULT_NUMBER_OF_THREADS = 4321;
@Test
public void shouldExtractTargetRef() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF));
final BulkImportParameters params = extractor.extract();
assertNotNull(params);
assertNotNull(params.getTarget());
assertEquals(TEST_NODE_REF, params.getTarget().toString());
}
@Test
public void shouldFallbackToDefaultValues() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF));
final BulkImportParameters params = extractor.extract();
assertEquals(DEFAULT_BATCH_SIZE, params.getBatchSize());
assertEquals(DEFAULT_NUMBER_OF_THREADS, params.getNumThreads());
assertFalse(params.isDisableRulesService());
assertEquals(ExistingFileMode.SKIP, params.getExistingFileMode());
assertNull(params.getLoggingInterval());
}
@Test
public void shouldExtractDisableFolderRulesFlagWhenSetToTrue() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_DISABLE_RULES, "true"
));
final BulkImportParameters params = extractor.extract();
assertTrue(params.isDisableRulesService());
}
@Test
public void shouldExtractDisableFolderRulesFlagWhenSetToFalse() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_DISABLE_RULES, "false"
));
final BulkImportParameters params = extractor.extract();
assertFalse(params.isDisableRulesService());
}
@Test
public void shouldExtractDisableFolderRulesFlagWhenSetToNotBooleanValue() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_DISABLE_RULES, "unknown"
));
final BulkImportParameters params = extractor.extract();
assertFalse(params.isDisableRulesService());
}
@Test
public void shouldPropagateFileNotFoundExceptionWhenTargetIsNotFound()
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_MISSING_NODE_REF));
assertThrows(FileNotFoundException.class, extractor::extract);
}
@Test
public void shouldExtractValidBatchSize() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_BATCH_SIZE, "1"));
final BulkImportParameters params = extractor.extract();
assertEquals(Integer.valueOf(1), params.getBatchSize());
}
@Test
public void shouldFailWithWebScriptExceptionWhenInvalidBatchSizeIsRequested() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_BATCH_SIZE, "not-a-number"));
try
{
extractor.extract();
} catch (WebScriptException e)
{
assertNotNull(e.getMessage());
assertTrue(e.getMessage().contains(PARAMETER_BATCH_SIZE));
return;
}
fail("Expected exception to be thrown.");
}
@Test
public void shouldFailWithWebScriptExceptionWhenNegativeBatchSizeIsRequested() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_BATCH_SIZE, "-1"));
try
{
extractor.extract();
} catch (WebScriptException e)
{
assertNotNull(e.getMessage());
assertTrue(e.getMessage().contains(PARAMETER_BATCH_SIZE));
return;
}
fail("Expected exception to be thrown.");
}
@Test
public void shouldExtractValidNumberOfThreads() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_NUM_THREADS, "1"));
final BulkImportParameters params = extractor.extract();
assertEquals(Integer.valueOf(1), params.getNumThreads());
}
@Test
public void shouldFailWithWebScriptExceptionWhenInvalidNumberOfThreadsIsRequested() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_NUM_THREADS, "not-a-number"));
try
{
extractor.extract();
} catch (WebScriptException e)
{
assertNotNull(e.getMessage());
assertTrue(e.getMessage().contains(PARAMETER_NUM_THREADS));
return;
}
fail("Expected exception to be thrown.");
}
@Test
public void shouldFailWithWebScriptExceptionWhenNegativeNumberOfThreadsIsRequested() throws FileNotFoundException
{
final BulkImportParametersExtractor extractor = givenExtractor(Map.of(
PARAMETER_TARGET_NODEREF, TEST_NODE_REF,
PARAMETER_NUM_THREADS, "-1"));
try
{
extractor.extract();
} catch (WebScriptException e)
{
assertNotNull(e.getMessage());
assertTrue(e.getMessage().contains(PARAMETER_NUM_THREADS));
return;
}
fail("Expected exception to be thrown.");
}
private BulkImportParametersExtractor givenExtractor(Map<String, String> params)
{
return new BulkImportParametersExtractor(params::get, this::testRefCreator, DEFAULT_BATCH_SIZE, DEFAULT_NUMBER_OF_THREADS);
}
private NodeRef testRefCreator(String nodeRef, String path) throws FileNotFoundException
{
if (TEST_MISSING_NODE_REF.equals(nodeRef))
{
throw new FileNotFoundException(new NodeRef(nodeRef));
}
return new NodeRef(nodeRef);
}
}

View File

@@ -7,7 +7,7 @@
<parent>
<groupId>org.alfresco</groupId>
<artifactId>alfresco-community-repo</artifactId>
<version>11.141-SNAPSHOT</version>
<version>12.9</version>
</parent>
<dependencies>

View File

@@ -415,12 +415,13 @@ implements TenantDeployer, DictionaryListener, /*TenantDictionaryListener, */Mes
for (NodeRef messageResource : nodeRefs)
{
String resourceName = (String) nodeService.getProperty(messageResource, ContentModel.PROP_NAME);
String bundleBaseName = messageService.getBaseBundleName(resourceName);
String messageResourcePath = nodeService.getPath(messageResource).toPrefixString(namespaceService);
String bundleBasePrefixedName = messageResourcePath.substring(messageResourcePath.lastIndexOf("/"));
String bundleBaseName = messageService.getBaseBundleName(bundleBasePrefixedName);
if (!resourceBundleBaseNames.contains(bundleBaseName))
{
messageService.registerResourceBundle(storeRef.toString() + repositoryLocation.getPath() + bundleBaseName);
resourceBundleBaseNames.add(bundleBaseName);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -683,6 +683,7 @@ public class RenditionServiceImpl implements
log.debug("OnContentUpdate calling RenditionService2.render(\""+sourceNodeRef+"\", \""+renditionName+"\" so we switch to the new service.");
}
useRenditionService2 = true;
renditionService2.clearRenditionContentData(sourceNodeRef, renditionName);
renditionService2.render(sourceNodeRef, renditionName);
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2020 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -538,9 +538,8 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
}
if (logger.isDebugEnabled())
{
logger.debug("Set rendition hashcode " + transformContentHashCode + " and ThumbnailLastModified for " + renditionName);
logger.debug("Set ThumbnailLastModified for " + renditionName);
}
nodeService.setProperty(renditionNode, RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE, transformContentHashCode);
setThumbnailLastModified(sourceNodeRef, renditionName);
if (transformInputStream != null)
@@ -554,6 +553,11 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
contentWriter.setEncoding(DEFAULT_ENCODING);
ContentWriter renditionWriter = contentWriter;
renditionWriter.putContent(transformInputStream);
if (logger.isDebugEnabled())
{
logger.debug("Set rendition hashcode for " + renditionName);
}
nodeService.setProperty(renditionNode, RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE, transformContentHashCode);
}
catch (Exception e)
{
@@ -563,16 +567,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
}
else
{
Serializable content = nodeService.getProperty(renditionNode, PROP_CONTENT);
if (content != null)
{
nodeService.removeProperty(renditionNode, PROP_CONTENT);
nodeService.removeProperty(renditionNode, PROP_RENDITION_CONTENT_HASH_CODE);
if (logger.isDebugEnabled())
{
logger.debug("Cleared rendition content and hashcode");
}
}
clearRenditionContentData(renditionNode);
}
if (!sourceHasAspectRenditioned)
@@ -736,6 +731,43 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
}
}
/**
* Clears source nodeRef rendition content and content hash code using supplied rendition name
*
* @param sourceNodeRef
* @param renditionName
*/
public void clearRenditionContentData(NodeRef sourceNodeRef, String renditionName)
{
clearRenditionContentData(getRenditionNode(sourceNodeRef, renditionName));
}
/**
* Clears supplied rendition node content (if exists) and content hash code
*
* @param renditionNode
*/
private void clearRenditionContentData(NodeRef renditionNode)
{
if (renditionNode != null)
{
Serializable content = nodeService.getProperty(renditionNode, PROP_CONTENT);
if (content != null)
{
nodeService.removeProperty(renditionNode, PROP_CONTENT);
if (logger.isDebugEnabled())
{
logger.debug("Cleared rendition content");
}
}
nodeService.removeProperty(renditionNode, PROP_RENDITION_CONTENT_HASH_CODE);
if (logger.isDebugEnabled())
{
logger.debug("Cleared rendition hashcode");
}
}
}
/**
* This method checks whether the specified source node is of a content class which has been registered for
* rendition prevention.
@@ -886,6 +918,7 @@ public class RenditionService2Impl implements RenditionService2, InitializingBea
RenditionDefinition2 renditionDefinition = renditionDefinitionRegistry2.getRenditionDefinition(renditionName);
if (renditionDefinition != null)
{
clearRenditionContentData(sourceNodeRef, renditionName);
render(sourceNodeRef, renditionName);
}
else

View File

@@ -1,30 +1,33 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.security.permissions.impl.acegi;
import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.getNodeRef;
import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.shouldAbstainOrDeny;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
@@ -46,8 +49,6 @@ import org.alfresco.repo.security.permissions.impl.SimplePermissionReference;
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.AccessStatus;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.AuthorityService;
import org.alfresco.service.cmr.security.OwnableService;
@@ -59,6 +60,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* @author andyh
*/
@@ -395,61 +397,53 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean
{
throw new ACLEntryVoterException("The specified parameter is not a NodeRef or ChildAssociationRef");
}
else if (StoreRef.class.isAssignableFrom(params[cad.parameter[0]]))
if (List.class.isAssignableFrom(params[cad.parameter[0]]))
{
StoreRef storeRef = getArgument(invocation, cad.parameter[0]);
if (storeRef != null)
List<?> listArgument = getArgument(invocation, cad.parameter[0]);
if (listArgument != null)
{
if (log.isDebugEnabled())
NodeRef listNodeRef;
Integer accessAbstainOrDeny = null;
for (Object listElement : listArgument)
{
log.debug("\tPermission test against the store - using permissions on the root node");
}
if (nodeService.exists(storeRef))
{
testNodeRef = nodeService.getRootNode(storeRef);
}
}
}
else if (NodeRef.class.isAssignableFrom(params[cad.parameter[0]]))
{
testNodeRef = getArgument(invocation, cad.parameter[0]);
if (log.isDebugEnabled())
{
if (testNodeRef != null)
{
if (nodeService.exists(testNodeRef))
listNodeRef = getNodeRef(listElement, nodeService);
Integer currentValue = shouldAbstainOrDeny(cad.required, listNodeRef, abstainForClassQNames, nodeService, permissionService);
if (currentValue != null)
{
log.debug("\tPermission test on node " + nodeService.getPath(testNodeRef));
if (currentValue == AccessDecisionVoter.ACCESS_DENIED)
{
return AccessDecisionVoter.ACCESS_DENIED;
}
else
{
accessAbstainOrDeny = currentValue;
}
}
else
{
log.debug("\tPermission test on non-existing node " +testNodeRef);
}
}
}
}
else if (ChildAssociationRef.class.isAssignableFrom(params[cad.parameter[0]]))
{
ChildAssociationRef testChildRef = getArgument(invocation, cad.parameter[0]);
if (testChildRef != null)
{
testNodeRef = testChildRef.getChildRef();
if (log.isDebugEnabled())
if (accessAbstainOrDeny != null)
{
if (nodeService.exists(testNodeRef))
{
log.debug("\tPermission test on node " + nodeService.getPath(testNodeRef));
}
else
{
log.debug("\tPermission test on non-existing node " + testNodeRef);
}
return accessAbstainOrDeny;
}
if((hasMethodEntry == null) || (hasMethodEntry.booleanValue()))
{
return AccessDecisionVoter.ACCESS_GRANTED;
}
else
{
return AccessDecisionVoter.ACCESS_DENIED;
}
}
}
else
{
throw new ACLEntryVoterException("The specified parameter is not a NodeRef or ChildAssociationRef");
Object testObject = getArgument(invocation, cad.parameter[0]);
//If the execution reaches here, then testNodeRef is always null
testNodeRef = getNodeRef(testObject, nodeService);
}
}
else if (cad.typeString.equals(ACL_ITEM))
@@ -584,44 +578,10 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean
}
}
if (testNodeRef != null)
Integer accessAbstainOrDeny = shouldAbstainOrDeny(cad.required, testNodeRef, abstainForClassQNames, nodeService, permissionService);
if (accessAbstainOrDeny != null)
{
// now we know the node - we can abstain for certain types and aspects (eg. RM)
if(abstainForClassQNames.size() > 0)
{
// check node exists
if (nodeService.exists(testNodeRef))
{
QName typeQName = nodeService.getType(testNodeRef);
if(abstainForClassQNames.contains(typeQName))
{
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
Set<QName> aspectQNames = nodeService.getAspects(testNodeRef);
for(QName abstain : abstainForClassQNames)
{
if(aspectQNames.contains(abstain))
{
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
}
}
}
if (log.isDebugEnabled())
{
log.debug("\t\tNode ref is not null");
}
if (permissionService.hasPermission(testNodeRef, cad.required.toString()) == AccessStatus.DENIED)
{
if (log.isDebugEnabled())
{
log.debug("\t\tPermission is denied");
Thread.dumpStack();
}
return AccessDecisionVoter.ACCESS_DENIED;
}
return accessAbstainOrDeny;
}
}

View File

@@ -0,0 +1,175 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.security.permissions.impl.acegi;
import java.util.Set;
import net.sf.acegisecurity.vote.AccessDecisionVoter;
import org.alfresco.repo.security.permissions.impl.SimplePermissionReference;
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.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Utility methods extracted from AclEntryVoter
*
* @author Lev Belava
*/
final class ACLEntryVoterUtils
{
private static final Logger LOG = LoggerFactory.getLogger(ACLEntryVoterUtils.class);
private ACLEntryVoterUtils()
{
}
/**
* Gets NodeRef for testObject based on inferred type
*
* @param testObject Tested object to work on
* @param nodeService Node service to perform checks on refs
* @return NodeRef for testObject or null if (testObject is null or StoreRef from testObject does not exist in the provided NodeService)
* @throws ACLEntryVoterException if testObject is not null and not one of a NodeRef or ChildAssociationRef types
*/
static NodeRef getNodeRef(Object testObject, NodeService nodeService)
{
if (testObject == null)
{
return null;
}
if (StoreRef.class.isAssignableFrom(testObject.getClass()))
{
LOG.debug("Permission test against the store - using permissions on the root node");
StoreRef storeRef = (StoreRef) testObject;
if (nodeService.exists(storeRef))
{
return nodeService.getRootNode(storeRef);
}
else
{
LOG.debug("StoreRef does not exist");
return null;
}
}
if (NodeRef.class.isAssignableFrom(testObject.getClass()))
{
NodeRef result = (NodeRef) testObject;
if (LOG.isDebugEnabled())
{
if (nodeService.exists(result))
{
LOG.debug("Permission test on node {}", nodeService.getPath(result));
}
else
{
LOG.debug("Permission test on non-existing node {}", result);
}
}
return result;
}
if (ChildAssociationRef.class.isAssignableFrom(testObject.getClass()))
{
ChildAssociationRef testChildRef = (ChildAssociationRef) testObject;
NodeRef result = testChildRef.getChildRef();
if (LOG.isDebugEnabled())
{
if (nodeService.exists(result))
{
LOG.debug("Permission test on node {}", nodeService.getPath(result));
}
else
{
LOG.debug("Permission test on non-existing node {}", result);
}
}
return result;
}
throw new ACLEntryVoterException("The specified parameter is not a NodeRef or ChildAssociationRef");
}
/**
* Checks if tested NodeRef instance is abstained or denied based on set of QNames to abstain and
*
* @param requiredPermissionReference Required permissions
* @param testNodeRef NodeRef to be verified
* @param abstainForClassQNames Set of QNames to abstain
* @param nodeService Node service to perform checks on tested NodeRef
* @param permissionService Permission service to check for required permissions
* @return null if testNodeRef is not abstained or denied, otherwise returns appropriate status.
*/
static Integer shouldAbstainOrDeny(SimplePermissionReference requiredPermissionReference, NodeRef testNodeRef, Set<QName> abstainForClassQNames,
NodeService nodeService, PermissionService permissionService)
{
if (testNodeRef == null)
{
return null;
}
LOG.debug("Node ref is not null");
if (abstainForClassQNames.size() > 0 && nodeService.exists(testNodeRef))
{
if (abstainForClassQNames.contains(nodeService.getType(testNodeRef)))
{
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
Set<QName> testNodeRefAspects = nodeService.getAspects(testNodeRef);
for (QName abstain : abstainForClassQNames)
{
if (testNodeRefAspects.contains(abstain))
{
return AccessDecisionVoter.ACCESS_ABSTAIN;
}
}
}
if (AccessStatus.DENIED == permissionService.hasPermission(testNodeRef, requiredPermissionReference.toString()))
{
if (LOG.isDebugEnabled())
{
LOG.debug("Permission is denied");
Thread.dumpStack();
}
return AccessDecisionVoter.ACCESS_DENIED;
}
return null;
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2017 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -640,7 +640,7 @@ public class ThumbnailServiceImpl implements ThumbnailService,
boolean valid = true;
ContentData content = (ContentData) this.nodeService.getProperty(thumbnailNode, ContentModel.PROP_CONTENT);
// (MNT-17162) A thumbnail with an empty content is cached for post-transaction removal, to prevent the delete in read-only transactions.
if (content.getSize() == 0)
if (content == null || content.getSize() == 0)
{
TransactionalResourceHelper.getSet(THUMBNAIL_TO_DELETE_NODES).add(thumbnailNode);
TransactionSupportUtil.bindListener(this.thumbnailsToDeleteTransactionListener, 0);

View File

@@ -3,7 +3,7 @@
repository.name=Main Repository
# Schema number
version.schema=15002
version.schema=15100
# Directory configuration

View File

@@ -209,6 +209,7 @@ import org.junit.runners.Suite;
org.alfresco.repo.security.authentication.AuthorizationTest.class,
org.alfresco.repo.security.permissions.PermissionCheckedCollectionTest.class,
org.alfresco.repo.security.permissions.impl.acegi.FilteringResultSetTest.class,
org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtilsTest.class,
org.alfresco.repo.security.authentication.ChainingAuthenticationServiceTest.class,
org.alfresco.repo.security.authentication.NameBasedUserNameGeneratorTest.class,
org.alfresco.repo.version.common.VersionImplTest.class,

View File

@@ -31,17 +31,18 @@ import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.dictionary.DictionaryDAO;
import org.alfresco.repo.dictionary.NamespaceDAO;
import org.alfresco.repo.i18n.MessageService;
import org.alfresco.repo.node.db.DbNodeServiceImpl;
import org.alfresco.repo.policy.BehaviourFilter;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -50,6 +51,7 @@ import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransacti
import org.alfresco.service.cmr.admin.RepoAdminService;
import org.alfresco.service.cmr.dictionary.ClassDefinition;
import org.alfresco.service.cmr.dictionary.DictionaryService;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.ContentService;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -67,6 +69,8 @@ import org.apache.commons.logging.LogFactory;
import org.junit.experimental.categories.Category;
import org.springframework.context.ApplicationContext;
import junit.framework.TestCase;
/**
* @see RepoAdminServiceImpl
*
@@ -88,6 +92,7 @@ public class RepoAdminServiceImplTest extends TestCase
private NamespaceService namespaceService;
private BehaviourFilter behaviourFilter;
private DictionaryDAO dictionaryDAO;
private MessageService messageService;
final String modelPrefix = "model-";
final static String MKR = "{MKR}";
@@ -140,6 +145,7 @@ public class RepoAdminServiceImplTest extends TestCase
namespaceService = (NamespaceService) ctx.getBean("NamespaceService");
behaviourFilter = (BehaviourFilter)ctx.getBean("policyBehaviourFilter");
dictionaryDAO = (DictionaryDAO) ctx.getBean("dictionaryDAO");
messageService = (MessageService) ctx.getBean("MessageService");
DbNodeServiceImpl dbNodeService = (DbNodeServiceImpl)ctx.getBean("dbNodeService");
dbNodeService.setEnableTimestampPropagation(false);
@@ -865,8 +871,182 @@ public class RepoAdminServiceImplTest extends TestCase
}
}
}
//
// TODO - Test custom message management
//
// Test deploy bundle from classpath
public void testDeployMessageBundleFromClasspath() throws Exception
{
String bundleBaseName = "mycustommessages";
String resourceClasspath = "alfresco/extension/messages/" + bundleBaseName;
final String message_key = "mycustommessages.key1";
final String message_value_default = "This is a custom message";
final String message_value_fr = "Ceci est un message personnalis\\u00e9";
final String message_value_de = "Dies ist eine benutzerdefinierte Nachricht";
// Undeploy the bundle
if (repoAdminService.getMessageBundles().contains(bundleBaseName))
{
repoAdminService.undeployMessageBundle(bundleBaseName);
}
// Verify the custom bundle is registered
assertFalse("The custom bundle should not be deployed", repoAdminService.getMessageBundles().contains(bundleBaseName));
// Depoly the message bundle
repoAdminService.deployMessageBundle(resourceClasspath);
// Reload the messages
repoAdminService.reloadMessageBundle(bundleBaseName);
// Verify the custom bundle is registered
assertTrue("The custom bundle should be deployed", repoAdminService.getMessageBundles().contains(bundleBaseName));
// Verify we have the messages for each locale
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
assertMessageValue("Cannot retrieve default message value", message_value_default, message_key, Locale.getDefault());
assertMessageValue("Cannot retrieve french message value", message_value_fr, message_key, Locale.FRANCE);
assertMessageValue("Cannot retrieve german message value", message_value_de, message_key, Locale.GERMANY);
// Test deploy a non existent bundle
try
{
repoAdminService.deployMessageBundle("alfresco/extension/messages/inexistentbundle");
fail("Bundle was not supposed to be deployed");
}
catch (Exception e)
{
// Expected to fail
}
}
// Test deploy bundle from repo and reload bundles
public void testDeployMessageBundleFromRepo() throws Exception
{
final String bundleBaseName = "repoBundle";
final String message_key = "repoBundle.key1";
final String message_value = "Value 1";
final String message_value_fr = "Value FR";
final String message_value_de = "Value DE";
final String message_value_new = "New Value 1";
// Set location
NodeRef rootNodeRef = nodeService.getRootNode(StoreRef.STORE_REF_WORKSPACE_SPACESSTORE);
List<NodeRef> nodeRefs = searchService.selectNodes(rootNodeRef, "/app:company_home/app:dictionary/app:messages", null,
namespaceService, false);
assertEquals(1, nodeRefs.size());
NodeRef messagesNodeRef = nodeRefs.get(0);
// Clear messages of this bundle if they exist and are registered
clearRepoBundles(messagesNodeRef);
assertEquals(0, repoAdminService.getMessageBundles().size());
// Create and upload the message files
NodeRef messageNode_default = createMessagesNodeWithSingleKey(messagesNodeRef, bundleBaseName, message_key, null,
message_value);
createMessagesNodeWithSingleKey(messagesNodeRef, bundleBaseName, message_key, Locale.FRANCE.toString(), message_value_fr);
createMessagesNodeWithSingleKey(messagesNodeRef, bundleBaseName, message_key, Locale.GERMANY.toString(),
message_value_de);
// Reload the messages
repoAdminService.reloadMessageBundle(bundleBaseName);
// Verify we have the messages for each locale
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getAdminUserName());
assertMessageValue("Cannot retrieve default message value", message_value, message_key, Locale.getDefault());
assertMessageValue("Cannot retrieve french message value", message_value_fr, message_key, Locale.FRANCE);
assertMessageValue("Cannot retrieve german message value", message_value_de, message_key, Locale.GERMANY);
// Change the values
putContentInMessageNode(messageNode_default, message_key, message_value_new);
// Verify we still have the old value
assertMessageValue("Unexpected change of message value", message_value, message_key, Locale.getDefault());
// Reload the messages
repoAdminService.reloadMessageBundle(bundleBaseName);
// Verify new values
assertMessageValue("Change of message value not reflected", message_value_new, message_key, Locale.getDefault());
}
/**
* Create messages node
*/
private NodeRef createMessagesNodeWithSingleKey(NodeRef parentNode, String bundleName, String key, String locale,
String localeValue)
{
String msg_extension = ".properties";
String filename = bundleName + msg_extension;
String messageValue = localeValue;
if (locale != null)
{
filename = bundleName + "_" + locale + msg_extension;
}
// Create a model node
NodeRef messageNode = this.nodeService.createNode(
parentNode,
ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, filename),
ContentModel.TYPE_CONTENT,
Collections.<QName, Serializable> singletonMap(ContentModel.PROP_NAME, filename)
).getChildRef();
putContentInMessageNode(messageNode, key, messageValue);
return messageNode;
}
/**
* Write content of message node
*/
private void putContentInMessageNode(NodeRef nodeRef, String key, String value)
{
ContentWriter contentWriter = contentService.getWriter(nodeRef, ContentModel.PROP_CONTENT, true);
contentWriter.setEncoding("UTF-8");
contentWriter.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
String messagesString = key + "=" + value;
contentWriter.putContent(messagesString);
}
/**
* Clear Repo Bundle
*/
private void clearRepoBundles(NodeRef parentNode)
{
List<String> repoBundles = repoAdminService.getMessageBundles();
for (String repoBundle : repoBundles)
{
repoAdminService.undeployMessageBundle(repoBundle);
}
List<ChildAssociationRef> messageNodes = nodeService.getChildAssocs(parentNode);
for (ChildAssociationRef messageChildRef : messageNodes)
{
NodeRef messageNode = messageChildRef.getChildRef();
nodeService.deleteNode(messageNode);
}
}
/**
* Clear Repo Bundle
*/
private void assertMessageValue(String errorMessage, String expectedValue, String key, Locale locale)
{
transactionService.getRetryingTransactionHelper()
.doInTransaction(new RetryingTransactionHelper.RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
assertEquals(errorMessage, expectedValue, messageService.getMessage(key, locale));
return null;
}
});
}
}

View File

@@ -25,9 +25,14 @@
*/
package org.alfresco.repo.dictionary;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import javax.transaction.UserTransaction;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
@@ -53,8 +58,6 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import javax.transaction.UserTransaction;
import org.springframework.transaction.annotation.Transactional;
@Category(BaseSpringTestsCategory.class)
@@ -94,6 +97,14 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
"</model>";
public static final String MESSAGES_KEY = "my_bootstrap_test";
public static final String MESSAGES_VALUE = "My Message";
public static final String MESSAGES_VALUE_FR = "Mon message";
public static final String FOLDERNAME_MODELS = "models";
public static final String FOLDERNAME_MESSAGES = "messages";
public static final String BUNDLENAME_MESSAGES = "testBootstap";
public static final String FILENAME_MESSAGES_EXT = ".properties";
/** Behaviour filter */
private BehaviourFilter behaviourFilter;
@@ -123,7 +134,8 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
private UserTransaction txn;
private StoreRef storeRef;
private NodeRef rootNodeRef;
private NodeRef rootModelsNodeRef;
private NodeRef rootMessagesNodeRef;
@Before
public void before() throws Exception
@@ -151,7 +163,17 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
// Create the store and get the root node
this.storeRef = this.nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.currentTimeMillis());
this.rootNodeRef = this.nodeService.getRootNode(this.storeRef);
NodeRef rootNodeRef = this.nodeService.getRootNode(this.storeRef);
this.rootModelsNodeRef = this.nodeService
.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, FOLDERNAME_MODELS), ContentModel.TYPE_FOLDER)
.getChildRef();
this.rootMessagesNodeRef = this.nodeService
.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, FOLDERNAME_MESSAGES), ContentModel.TYPE_FOLDER)
.getChildRef();
txn.commit();
@@ -167,18 +189,20 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
this.bootstrap.setNamespaceService(this.namespaceService);
this.bootstrap.setMessageService(this.messageService);
this.bootstrap.setPolicyComponent(this.policyComponent);
RepositoryLocation location = new RepositoryLocation();
location.setStoreProtocol(this.storeRef.getProtocol());
location.setStoreId(this.storeRef.getIdentifier());
location.setQueryLanguage(RepositoryLocation.LANGUAGE_PATH);
// NOTE: we are not setting the path for now .. in doing so we are searching the root node only
List<RepositoryLocation> locations = new ArrayList<RepositoryLocation>();
locations.add(location);
this.bootstrap.setRepositoryModelsLocations(locations);
RepositoryLocation modelsLocation = new RepositoryLocation(this.storeRef,
this.nodeService.getPath(rootModelsNodeRef).toPrefixString(namespaceService), RepositoryLocation.LANGUAGE_PATH);
RepositoryLocation messagesLocation = new RepositoryLocation(this.storeRef,
this.nodeService.getPath(rootMessagesNodeRef).toPrefixString(namespaceService), RepositoryLocation.LANGUAGE_PATH);
List<RepositoryLocation> modelsLocations = new ArrayList<RepositoryLocation>();
modelsLocations.add(modelsLocation);
List<RepositoryLocation> messagesLocations = new ArrayList<RepositoryLocation>();
messagesLocations.add(messagesLocation);
this.bootstrap.setRepositoryModelsLocations(modelsLocations);
this.bootstrap.setRepositoryMessagesLocations(messagesLocations);
// register with dictionary service
this.bootstrap.register();
txn.commit();
@@ -224,7 +248,15 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
"Test model one",
"base1",
"prop1");
// Create a message file for the default locale
NodeRef messageNodeDefaultLoc = createMessagesNode(null, null);
// Create a message file for the french locale
createMessagesNode(Locale.FRANCE.toString(), MESSAGES_VALUE_FR);
// Construct baseBundleName for validation
String baseBundleName = storeRef.toString()
+ messageService.getBaseBundleName(nodeService.getPath(messageNodeDefaultLoc).toPrefixString(namespaceService));
// Check that the model is not in the dictionary yet
try
{
@@ -251,6 +283,12 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
QName.createQName("http://www.alfresco.org/model/test3DictionaryBootstrapFromRepo/1.0", "testModel3"));
assertNotNull(modelDefinition3);
// Check if the messages were registered correctly
assertTrue("The message bundle should be registered", messageService.getRegisteredBundles().contains(baseBundleName));
assertEquals("The default message value is not as expected", MESSAGES_VALUE, messageService.getMessage(MESSAGES_KEY));
assertEquals("The message value in french is not as expected", MESSAGES_VALUE_FR,
messageService.getMessage(MESSAGES_KEY, Locale.FRANCE));
txn.commit();
}
@@ -277,7 +315,7 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
{
// Create a model node
NodeRef model = this.nodeService.createNode(
this.rootNodeRef,
this.rootModelsNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName("{test}models"),
ContentModel.TYPE_DICTIONARY_MODEL).getChildRef();
@@ -300,6 +338,39 @@ public class DictionaryRepositoryBootstrapTest extends BaseSpringTest
return model;
}
/**
* Create messages node
*
* @return NodeRef
*/
private NodeRef createMessagesNode(String locale, String localeValue)
{
String filename = BUNDLENAME_MESSAGES + FILENAME_MESSAGES_EXT;
String messageValue = MESSAGES_VALUE;
if (locale != null)
{
filename = BUNDLENAME_MESSAGES + "_" + locale + FILENAME_MESSAGES_EXT;
messageValue = localeValue;
}
// Create a model node
NodeRef messageNode = this.nodeService.createNode(
this.rootMessagesNodeRef,
ContentModel.ASSOC_CHILDREN,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, filename),
ContentModel.TYPE_CONTENT,
Collections.<QName, Serializable> singletonMap(ContentModel.PROP_NAME, filename)
).getChildRef();
ContentWriter contentWriter = this.contentService.getWriter(messageNode, ContentModel.PROP_CONTENT, true);
contentWriter.setEncoding("UTF-8");
contentWriter.setMimetype(MimetypeMap.MIMETYPE_TEXT_PLAIN);
String messagesString = MESSAGES_KEY + "=" + messageValue;
contentWriter.putContent(messagesString);
return messageNode;
}
/**
*
* Gets the model string

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* Copyright (C) 2005 - 2021 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,7 +25,16 @@
*/
package org.alfresco.repo.rendition2;
import junit.framework.AssertionFailedError;
import static java.lang.Thread.sleep;
import static org.alfresco.model.ContentModel.PROP_CONTENT;
import static org.alfresco.model.RenditionModel.PROP_RENDITION_CONTENT_HASH_CODE;
import static org.alfresco.repo.content.MimetypeMap.EXTENSION_BINARY;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.Serializable;
import java.util.Collections;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.metadata.AsynchronousExtractor;
@@ -60,15 +69,7 @@ import org.quartz.CronExpression;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.Serializable;
import java.util.Collections;
import java.util.Map;
import static java.lang.Thread.sleep;
import static org.alfresco.model.ContentModel.PROP_CONTENT;
import static org.alfresco.repo.content.MimetypeMap.EXTENSION_BINARY;
import junit.framework.AssertionFailedError;
/**
* Class unites common utility methods for {@link org.alfresco.repo.rendition2} package tests.
@@ -531,4 +532,41 @@ public abstract class AbstractRenditionIntegrationTest extends BaseSpringTest
RetryingTransactionHelper txnHelper = transactionService.getRetryingTransactionHelper();
txnHelper.doInTransaction(createUserCallback);
}
/**
* Helper method to check if the supplied content hash code is valid or not
*
* @param contentHashCode
* the hash code to verify
*
* @return true in case it is an actual hash code, false otherwise
*/
protected boolean isValidRenditionContentHashCode(int contentHashCode)
{
return contentHashCode != RenditionService2Impl.RENDITION2_DOES_NOT_EXIST
&& contentHashCode != RenditionService2Impl.SOURCE_HAS_NO_CONTENT;
}
/**
* Helper method which gets the content hash code from the supplied rendition node without specific validations (the
* equivalent method from {@link RenditionService2Impl} is not exposed)
*
* @param renditionNodeRef
* the rendition node
*
* @return -1 in case of there is no content, -2 in case rendition doesn't exist, the actual content hash code
* otherwise
*/
protected int getRenditionContentHashCode(NodeRef renditionNodeRef)
{
int renditionContentHashCode = RenditionService2Impl.RENDITION2_DOES_NOT_EXIST;
if (renditionNodeRef != null)
{
Serializable hashCode = nodeService.getProperty(renditionNodeRef, PROP_RENDITION_CONTENT_HASH_CODE);
renditionContentHashCode = hashCode == null ? RenditionService2Impl.SOURCE_HAS_NO_CONTENT : (int) hashCode;
}
return renditionContentHashCode;
}
}

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2018 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -25,6 +25,11 @@
*/
package org.alfresco.repo.rendition2;
import static org.alfresco.model.ContentModel.PROP_CONTENT;
import static org.junit.Assert.assertNotEquals;
import java.util.List;
import org.alfresco.model.ContentModel;
import org.alfresco.model.RenditionModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
@@ -36,16 +41,9 @@ import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.NamespaceService;
import org.alfresco.service.namespace.QName;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.List;
import static org.alfresco.model.ContentModel.PROP_CONTENT;
import static org.junit.Assert.assertNotEquals;
/**
* Integration tests for {@link RenditionService2}
*/
@@ -308,6 +306,99 @@ public class RenditionService2IntegrationTest extends AbstractRenditionIntegrati
assertTrue("The rendition should be generated by new Rendition Service", hasRenditionedAspect);
}
/**
* Tests new {@link RenditionService2Impl#clearRenditionContentData(NodeRef, String)} method.
* <p>
* This method cleans a rendition content and content hash code.
* </p>
*/
@Test
public void testClearRenditionContentData()
{
// Create a node
NodeRef sourceNodeRef = createSource(ADMIN, "quick.jpg");
// Trigger the rendition
render(ADMIN, sourceNodeRef, DOC_LIB);
NodeRef renditionNodeRef = waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true);
assertNotNull("Rendition was not generated", renditionNodeRef);
assertNotNull("Rendition was not generated", nodeService.getProperty(renditionNodeRef, ContentModel.PROP_CONTENT));
// Check the rendition content hash code is valid
int contentHashCode = getRenditionContentHashCode(renditionNodeRef);
assertTrue("Rendition content hash code was not generated", isValidRenditionContentHashCode(contentHashCode));
// Disable renditionService2
renditionService2.setEnabled(false);
// Call 'clearRenditionContentData' method directly to prove rendition content will be cleaned
AuthenticationUtil.runAs((AuthenticationUtil.RunAsWork<Void>) () ->
transactionService.getRetryingTransactionHelper().doInTransaction(() ->
{
renditionService2.clearRenditionContentData(sourceNodeRef, DOC_LIB);
return null;
}), ADMIN);
// The rendition should not have content by now
assertNull("Rendition has content", nodeService.getProperty(renditionNodeRef, ContentModel.PROP_CONTENT));
// The rendition should not have a content hash code by now
contentHashCode = getRenditionContentHashCode(renditionNodeRef);
assertFalse("Rendition has content hash code", isValidRenditionContentHashCode(contentHashCode));
// Enable renditionService2
renditionService2.setEnabled(true);
}
/**
* Tests if a rendition without content (but with contentHashCode) can be generated again.
* <p>
* If the rendition consumption receives a null InputStream, the contentHashCode should be cleaned from the
* rendition node, allowing new requests to generate the rendition.
* </p>
*/
@Test
public void testRenditionWithoutContentButWithContentHashCode()
{
// Create a node with an actual rendition
NodeRef sourceNodeRef = createSource(ADMIN, "quick.jpg");
render(ADMIN, sourceNodeRef, DOC_LIB);
NodeRef renditionNodeRef = waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true);
assertNotNull("Rendition was not generated", renditionNodeRef);
assertNotNull("Rendition was not generated", nodeService.getProperty(renditionNodeRef, ContentModel.PROP_CONTENT));
// Clear rendition content (at this point we're forcing a rendition without content but with hash code)
clearContent(ADMIN, renditionNodeRef);
assertNull("Rendition has content", nodeService.getProperty(renditionNodeRef, ContentModel.PROP_CONTENT));
// Check that rendition still has the content hash code
final int contentHashCode = getRenditionContentHashCode(renditionNodeRef);
assertTrue("Rendition content hash code was not generated", isValidRenditionContentHashCode(contentHashCode));
// Call the 'consume' method directly supplying a null InputStream
// This is explicitly called to prove that rendition hash code will be cleaned (as opposite to previous behavior)
RenditionDefinition2 renditionDefinition = renditionDefinitionRegistry2.getRenditionDefinition(DOC_LIB);
AuthenticationUtil.runAs(() -> {
renditionService2.consume(sourceNodeRef, null, renditionDefinition, contentHashCode);
return null;
}, ADMIN);
waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, false);
// The content hash code should have been cleaned from the rendition node
int contentHashCode2 = getRenditionContentHashCode(renditionNodeRef);
assertFalse("Rendition content hash code was not cleaned", isValidRenditionContentHashCode(contentHashCode2));
// Attempts to render the rendition again
render(ADMIN, sourceNodeRef, DOC_LIB);
NodeRef renditionNodeRef2 = waitForRendition(ADMIN, sourceNodeRef, DOC_LIB, true);
assertEquals("New rendition nodeRef is different", renditionNodeRef.toString(), renditionNodeRef2.toString());
assertNotNull("New rendition content was not generated", nodeService.getProperty(renditionNodeRef2, ContentModel.PROP_CONTENT));
// Check the new rendition content hash code
int contentHashCode3 = getRenditionContentHashCode(renditionNodeRef2);
assertTrue("New rendition content hash code was not generated", isValidRenditionContentHashCode(contentHashCode3));
}
/**
* @deprecated can be removed when we remove the original RenditionService
*/

View File

@@ -2,7 +2,7 @@
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2016 Alfresco Software Limited
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
@@ -96,6 +96,8 @@ public abstract class AbstractPermissionTest extends TestCase
protected NodeRef systemNodeRef;
protected NodeRef abstainedNode;
protected AuthenticationComponent authenticationComponent;
protected ModelDAO permissionModelDAO;
@@ -186,6 +188,8 @@ public abstract class AbstractPermissionTest extends TestCase
props = createPersonProperties(USER2_LEMUR);
nodeService.createNode(typesNodeRef, children, ContentModel.TYPE_PERSON, container, props).getChildRef();
abstainedNode= nodeService.createNode(rootNodeRef, ContentModel.ASSOC_FAILED_THUMBNAIL, system, ContentModel.TYPE_FAILED_THUMBNAIL).getChildRef();
// create an authentication object e.g. the user
if(authenticationDAO.userExists(USER1_ANDY))
{

View File

@@ -0,0 +1,181 @@
/*
* #%L
* Alfresco Repository
* %%
* Copyright (C) 2005 - 2021 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* If the software was purchased under a paid Alfresco license, the terms of
* the paid license agreement will prevail. Otherwise, the software is
* provided under the following open source license terms:
*
* Alfresco is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Alfresco is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L%
*/
package org.alfresco.repo.security.permissions.impl.acegi;
import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.getNodeRef;
import static org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoterUtils.shouldAbstainOrDeny;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.when;
import java.util.Collections;
import java.util.Set;
import net.sf.acegisecurity.vote.AccessDecisionVoter;
import org.alfresco.repo.security.permissions.impl.SimplePermissionReference;
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.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class ACLEntryVoterUtilsTest
{
private final NodeRef testNodeRef = new NodeRef("workspace://testNodeRef/testNodeRef");
private final NodeRef rootNodeRef = new NodeRef("workspace://rootNodeRef/rootNodeRef");
private final NodeRef refNodeForTestObject = new NodeRef("workspace://refNodeForTestObject/refNodeForTestObject");
private final NodeRef childRefNode = new NodeRef("workspace://childRefNode/childRefNode");
private final StoreRef testStoreNodeRef = new StoreRef("system://testStoreRefMock/testStoreRefMock");
private final SimplePermissionReference simplePermissionReference = SimplePermissionReference.getPermissionReference(QName.createQName("uri", "local"), "Write");
private final QName qNameToAbstain1 = QName.createQName("{test}testnode1");
private final QName qNameToAbstain2 = QName.createQName("{test}testnode2");
private final QName qNameToAbstain3 = QName.createQName("{test}testnode3");
private final QName qNameNotFromTheAbstainSet = QName.createQName("{test}testnodeAbstain");
private final Set<QName> qNamesToAbstain = Set.of(qNameToAbstain1, qNameToAbstain2, qNameToAbstain3);
@Mock
private PermissionService permissionServiceMock;
@Mock
private NodeService nodeServiceMock;
@Mock
private ChildAssociationRef childAssocRefMock;
@Before
public void setUp()
{
when(nodeServiceMock.exists(testStoreNodeRef)).thenReturn(Boolean.TRUE);
when(nodeServiceMock.exists(testNodeRef)).thenReturn(Boolean.TRUE);
when(nodeServiceMock.getRootNode(testStoreNodeRef)).thenReturn(rootNodeRef);
when(nodeServiceMock.getType(testNodeRef)).thenReturn(qNameNotFromTheAbstainSet);
when(nodeServiceMock.getAspects(testNodeRef)).thenReturn(Set.of(qNameNotFromTheAbstainSet));
when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.DENIED);
}
@Test
public void returnsAccessDeniedFromPermissionService()
{
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(AccessDecisionVoter.ACCESS_DENIED));
}
@Test
public void returnsNullOnNullTestObject()
{
assertThat(getNodeRef(null, nodeServiceMock), is(nullValue()));
}
@Test(expected = ACLEntryVoterException.class)
public void throwsExceptionWhenParameterIsNotNodeRefOrChildAssociationRef()
{
getNodeRef("TEST", nodeServiceMock);
}
@Test
public void returnsGivenTestNodeRefWhenStoreRefDoesNotExist()
{
when(nodeServiceMock.exists(testStoreNodeRef)).thenReturn(Boolean.FALSE);
assertThat(getNodeRef(testStoreNodeRef, nodeServiceMock), is(nullValue()));
}
@Test
public void returnsRootNode()
{
assertThat(getNodeRef(testStoreNodeRef, nodeServiceMock), is(rootNodeRef));
}
@Test
public void returnsNodeRefFromTestObject()
{
assertThat(getNodeRef(refNodeForTestObject, nodeServiceMock), is(refNodeForTestObject));
}
@Test
public void returnsChildRefFromChildAssocRef()
{
when(childAssocRefMock.getChildRef()).thenReturn(childRefNode);
assertThat(getNodeRef(childAssocRefMock, nodeServiceMock), is(childRefNode));
}
@Test
public void returnsNullOnNullTestNodeRef()
{
assertThat(shouldAbstainOrDeny(simplePermissionReference, null, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(nullValue()));
}
@Test
public void returnsNullOnAbstainClassQnamesIsEmptyAndThereAreNoDeniedPermissions()
{
when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.ALLOWED);
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, Collections.emptySet(), nodeServiceMock, permissionServiceMock),
is(nullValue()));
}
@Test
public void returnsNullOnTestNodeRefDoesNotExistAndThereAreNoDeniedPermissions()
{
when(nodeServiceMock.exists(testNodeRef)).thenReturn(Boolean.FALSE);
when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.ALLOWED);
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(nullValue()));
}
@Test
public void returnsNullOnNodeTypeAndNodeAspectsAreNotInSetToAbstainAndThereAreNoDeniedPermissions()
{
when(permissionServiceMock.hasPermission(eq(testNodeRef), nullable(String.class))).thenReturn(AccessStatus.ALLOWED);
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(nullValue()));
}
@Test
public void returnsAbstainWhenNodeRefTypeIsInSetToAbstain()
{
when(nodeServiceMock.getType(testNodeRef)).thenReturn(qNameToAbstain2);
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(AccessDecisionVoter.ACCESS_ABSTAIN));
}
@Test
public void returnsAbstainWhenAtLeastOneAspectIsInSetToAbstain()
{
when(nodeServiceMock.getAspects(testNodeRef)).thenReturn(Set.of(qNameNotFromTheAbstainSet, qNameToAbstain3));
assertThat(shouldAbstainOrDeny(simplePermissionReference, testNodeRef, qNamesToAbstain, nodeServiceMock, permissionServiceMock),
is(AccessDecisionVoter.ACCESS_ABSTAIN));
}
}

View File

@@ -0,0 +1 @@
mycustommessages.key1=This is a custom message

View File

@@ -0,0 +1 @@
mycustommessages.key1=Dies ist eine benutzerdefinierte Nachricht

View File

@@ -0,0 +1 @@
mycustommessages.key1=Ceci est un message personnalis\u00e9