mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-09-10 14:11:58 +00:00
Compare commits
40 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
dfc9ea2f90 | ||
|
0696401f34 | ||
|
42e476891f | ||
|
95d2426af4 | ||
|
e2df0ca4b4 | ||
|
5a03bde0dc | ||
|
e8f44a14e3 | ||
|
a83fc912e7 | ||
|
57c5a1c01a | ||
|
e7cbd1d2a7 | ||
|
da6e87e001 | ||
|
4197c29fce | ||
|
3d4785d5ae | ||
|
6c68658476 | ||
|
1bd439e0ec | ||
|
72f84ee50b | ||
|
50f26b9137 | ||
|
b6b1cc3ea0 | ||
|
0f1c1cdba1 | ||
|
841bc6844e | ||
|
a5bdf47f00 | ||
|
a0b279d1ff | ||
|
fb967dfa9e | ||
|
f0a51e1347 | ||
|
42d56f9d20 | ||
|
3f31e4b1a2 | ||
|
787a331869 | ||
|
5ce3a3ddd6 | ||
|
9ed96ec593 | ||
|
03b1fa8b09 | ||
|
d69f9b52c3 | ||
|
72b910bb48 | ||
|
cfaf3b280b | ||
|
00d814ec55 | ||
|
becabb3a41 | ||
|
033157800b | ||
|
b9c8ff91e4 | ||
|
c54d46ab67 | ||
|
dec514c5c2 | ||
|
7c5a8a1963 |
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-automation-community-repo</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-parent</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-governance-services-community-repo-parent</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-amps</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -1,5 +1,6 @@
|
||||
const THUMBNAIL_NAME = "doclib",
|
||||
TYPE_SITES = "st:sites",
|
||||
SITES_PATH = "Sites/",
|
||||
PREF_DOCUMENT_FAVOURITES = "org.alfresco.share.documents.favourites",
|
||||
PREF_FOLDER_FAVOURITES = "org.alfresco.share.folders.favourites",
|
||||
LIKES_SCHEME = "likesRatingScheme";
|
||||
@@ -278,8 +279,39 @@ var ParseArgs =
|
||||
pathNode = path.length > 0 ? rootNode.childByNamePath(path) : (pathNode || rootNode);
|
||||
if (pathNode === null)
|
||||
{
|
||||
status.setCode(status.STATUS_NOT_FOUND, "Path not found: '" + path + "'");
|
||||
return null;
|
||||
// Path was not found in rootNode so a search attempt will be performed in companyHome
|
||||
pathNode = path.length > 0 ? companyhome.childByNamePath(path) : null;
|
||||
|
||||
// At this point, if path hasn't been found yet, a site search will be executed (if path first element is a site)
|
||||
if (pathNode === null)
|
||||
{
|
||||
if (path && path.length > 0)
|
||||
{
|
||||
var siteId;
|
||||
var idx = path.startsWith("/") ? 1 : 0;
|
||||
|
||||
if (idx >= 0)
|
||||
{
|
||||
siteId = path.split("/")[idx];
|
||||
if (siteId)
|
||||
{
|
||||
var siteNode = siteService.getSiteInfo(siteId);
|
||||
if (siteNode !== null)
|
||||
{
|
||||
path = SITES_PATH + path;
|
||||
pathNode = companyhome.childByNamePath(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If path node is still null, it wasn't possible to find it and STATUS_NOT_FOUND will be returned
|
||||
if (pathNode === null)
|
||||
{
|
||||
status.setCode(status.STATUS_NOT_FOUND, "Path not found: '" + path + "'");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parent location parameter adjustment
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -9,6 +9,6 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
</project>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<modules>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -9,7 +9,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-tests</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<developers>
|
||||
|
@@ -198,4 +198,15 @@ public class UnlockFileTests extends WebDavTest
|
||||
.then().unlock()
|
||||
.and().assertThat().hasStatus(HttpStatus.NO_CONTENT.value()).and().assertThat().isUnlocked();
|
||||
}
|
||||
|
||||
@TestRail(section={TestGroup.PROTOCOLS, TestGroup.WEBDAV}, executionType= ExecutionType.SANITY,
|
||||
description ="Checks no existent file is not locked (and status 404)")
|
||||
@Test(groups = {TestGroup.PROTOCOLS, TestGroup.WEBDAV, TestGroup.SANITY})
|
||||
public void checkLockStatusForNonExistentFile() throws Exception
|
||||
{
|
||||
testFile = FileModel.getRandomFileModel(FileType.TEXT_PLAIN, content);
|
||||
webDavProtocol.authenticateUser(dataUser.getAdminUser()).
|
||||
usingResource(testFile).
|
||||
assertThat().isUnlocked().assertThat().hasStatus(HttpStatus.NOT_FOUND.value());
|
||||
}
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo-packaging</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#%L
|
||||
Alfresco Repository WAR Community
|
||||
%%
|
||||
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
|
||||
@@ -35,15 +35,6 @@
|
||||
<%@ page import="org.alfresco.service.cmr.module.ModuleInstallState" %>
|
||||
<%@ page import="java.util.Calendar" %>
|
||||
|
||||
<!-- Enterprise index-jsp placeholder -->
|
||||
<%
|
||||
// route WebDAV requests
|
||||
if (request.getMethod().equalsIgnoreCase("PROPFIND") || request.getMethod().equalsIgnoreCase("OPTIONS"))
|
||||
{
|
||||
response.sendRedirect(request.getContextPath() + "/webdav/");
|
||||
}
|
||||
%>
|
||||
|
||||
<%
|
||||
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(session.getServletContext());
|
||||
SysAdminParams sysAdminParams = (SysAdminParams)context.getBean("sysAdminParams");
|
||||
|
8
pom.xml
8
pom.xml
@@ -2,7 +2,7 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</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.12</tag>
|
||||
</scm>
|
||||
|
||||
<distributionManagement>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
@@ -47,7 +47,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.santuario</groupId>
|
||||
<artifactId>xmlsec</artifactId>
|
||||
<version>1.5.8</version>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
<!-- newer version, see REPO-3133 -->
|
||||
<dependency>
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* #%L
|
||||
* Alfresco Remote API
|
||||
* %%
|
||||
* 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
|
||||
@@ -90,7 +90,8 @@ public abstract class CMISServletDispatcher implements CMISDispatcher
|
||||
protected CmisVersion cmisVersion;
|
||||
protected TenantAdminService tenantAdminService;
|
||||
|
||||
private Set<String> nonAttachContentTypes = Collections.emptySet(); // pre-configured whitelist, eg. images & pdf
|
||||
// pre-configured allow list of media/mime types, eg. specific types of images & also pdf
|
||||
private Set<String> nonAttachContentTypes = Collections.emptySet();
|
||||
|
||||
public void setTenantAdminService(TenantAdminService tenantAdminService)
|
||||
{
|
||||
@@ -137,9 +138,12 @@ public abstract class CMISServletDispatcher implements CMISDispatcher
|
||||
this.cmisVersion = CmisVersion.fromValue(cmisVersion);
|
||||
}
|
||||
|
||||
public void setNonAttachContentTypes(Set<String> nonAttachWhiteList)
|
||||
public void setNonAttachContentTypes(String nonAttachAllowListStr)
|
||||
{
|
||||
this.nonAttachContentTypes = nonAttachWhiteList;
|
||||
if ((nonAttachAllowListStr != null) && (! nonAttachAllowListStr.isEmpty()))
|
||||
{
|
||||
nonAttachContentTypes = Set.of(nonAttachAllowListStr.trim().split("\\s*,\\s*"));
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized Descriptor getCurrentDescriptor()
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -239,11 +239,15 @@ public class NodesImpl implements Nodes
|
||||
|
||||
private ConcurrentHashMap<String,NodeRef> ddCache = new ConcurrentHashMap<>();
|
||||
|
||||
private Set<String> nonAttachContentTypes = Collections.emptySet(); // pre-configured whitelist, eg. images & pdf
|
||||
// pre-configured allow list of media/mime types, eg. specific types of images & also pdf
|
||||
private Set<String> nonAttachContentTypes = Collections.emptySet();
|
||||
|
||||
public void setNonAttachContentTypes(Set<String> nonAttachWhiteList)
|
||||
public void setNonAttachContentTypes(String nonAttachAllowListStr)
|
||||
{
|
||||
this.nonAttachContentTypes = nonAttachWhiteList;
|
||||
if ((nonAttachAllowListStr != null) && (! nonAttachAllowListStr.isEmpty()))
|
||||
{
|
||||
nonAttachContentTypes = Set.of(nonAttachAllowListStr.trim().split("\\s*,\\s*"));
|
||||
}
|
||||
}
|
||||
|
||||
public void init()
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -508,19 +508,6 @@
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="nodes.nonAttachContentTypes" class="org.springframework.beans.factory.config.SetFactoryBean">
|
||||
<property name="sourceSet">
|
||||
<set>
|
||||
<value>application/pdf</value>
|
||||
<value>image/jpeg</value>
|
||||
<value>image/gif</value>
|
||||
<value>image/png</value>
|
||||
<value>image/tiff</value>
|
||||
<value>image/bmp</value>
|
||||
</set>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="nodes.personLookupProperties" class="org.springframework.beans.factory.config.SetFactoryBean">
|
||||
<property name="sourceSet">
|
||||
<set>
|
||||
@@ -541,7 +528,7 @@
|
||||
<property name="quickShareLinks" ref="QuickShareLinks"/>
|
||||
<property name="behaviourFilter" ref="policyBehaviourFilter"/>
|
||||
<property name="ignoreTypes" ref="nodes.ignoreTypes"/>
|
||||
<property name="nonAttachContentTypes" ref="nodes.nonAttachContentTypes"/>
|
||||
<property name="nonAttachContentTypes" value="${content.nonAttach.mimetypes}"/>
|
||||
<property name="personLookupProperties" ref="nodes.personLookupProperties"/>
|
||||
<property name="poster" ref="activitiesPoster" />
|
||||
<property name="smartStore" ref="smartStore"/>
|
||||
@@ -1070,7 +1057,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">
|
||||
@@ -1113,7 +1100,7 @@
|
||||
<property name="version" value="1.0"/>
|
||||
<property name="cmisVersion" value="1.0"/>
|
||||
<property name="tenantAdminService" ref="tenantAdminService"/>
|
||||
<property name="nonAttachContentTypes" ref="nodes.nonAttachContentTypes"/>
|
||||
<property name="nonAttachContentTypes" value="${content.nonAttach.mimetypes}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cmisAtomPubDispatcher1.1" class="org.alfresco.opencmis.PublicApiAtomPubCMISDispatcher" init-method="init">
|
||||
@@ -1125,7 +1112,7 @@
|
||||
<property name="version" value="1.1"/>
|
||||
<property name="cmisVersion" value="1.1"/>
|
||||
<property name="tenantAdminService" ref="tenantAdminService"/>
|
||||
<property name="nonAttachContentTypes" ref="nodes.nonAttachContentTypes"/>
|
||||
<property name="nonAttachContentTypes" value="${content.nonAttach.mimetypes}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="cmisBrowserDispatcher1.1" class="org.alfresco.opencmis.PublicApiBrowserCMISDispatcher" init-method="init">
|
||||
@@ -1137,7 +1124,7 @@
|
||||
<property name="version" value="1.1"/>
|
||||
<property name="cmisVersion" value="1.1"/>
|
||||
<property name="tenantAdminService" ref="tenantAdminService"/>
|
||||
<property name="nonAttachContentTypes" ref="nodes.nonAttachContentTypes"/>
|
||||
<property name="nonAttachContentTypes" value="${content.nonAttach.mimetypes}"/>
|
||||
</bean>
|
||||
|
||||
<bean id="webscript.org.alfresco.api.opencmis.OpenCMIS.get"
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.alfresco</groupId>
|
||||
<artifactId>alfresco-community-repo</artifactId>
|
||||
<version>11.141-SNAPSHOT</version>
|
||||
<version>12.12</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
|
@@ -28,6 +28,7 @@ package org.alfresco.repo.content;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -102,6 +103,9 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
|
||||
private boolean ignoreEmptyContent;
|
||||
|
||||
private SystemWideDirectUrlConfig systemWideDirectUrlConfig;
|
||||
|
||||
/** pre-configured allow list of media/mime types, eg. specific types of images & also pdf */
|
||||
private Set<String> nonAttachContentTypes = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* The policy component
|
||||
@@ -150,6 +154,14 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
|
||||
this.systemWideDirectUrlConfig = systemWideDirectUrlConfig;
|
||||
}
|
||||
|
||||
public void setNonAttachContentTypes(String nonAttachAllowListStr)
|
||||
{
|
||||
if ((nonAttachAllowListStr != null) && (! nonAttachAllowListStr.isEmpty()))
|
||||
{
|
||||
nonAttachContentTypes = Set.of(nonAttachAllowListStr.trim().split("\\s*,\\s*"));
|
||||
}
|
||||
}
|
||||
|
||||
public void setPolicyComponent(PolicyComponent policyComponent)
|
||||
{
|
||||
this.policyComponent = policyComponent;
|
||||
@@ -621,9 +633,19 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
|
||||
throw new DirectAccessUrlDisabledException("Direct access url isn't available.");
|
||||
}
|
||||
|
||||
String contentUrl = getContentUrl(nodeRef);
|
||||
ContentData contentData = getContentData(nodeRef, ContentModel.PROP_CONTENT);
|
||||
// check that the content & URL is available
|
||||
if (contentData == null || contentData.getContentUrl() == null)
|
||||
{
|
||||
throw new IllegalArgumentException("The supplied nodeRef " + nodeRef + " has no content.");
|
||||
}
|
||||
|
||||
String contentUrl = contentData.getContentUrl();
|
||||
String contentMimetype = contentData.getMimetype();
|
||||
String fileName = getFileName(nodeRef);
|
||||
|
||||
validFor = adjustValidFor(validFor);
|
||||
attachment = adjustAttachment(nodeRef, contentMimetype, attachment);
|
||||
|
||||
DirectAccessUrl directAccessUrl = null;
|
||||
if (store.isContentDirectUrlEnabled())
|
||||
@@ -676,4 +698,21 @@ public class ContentServiceImpl implements ContentService, ApplicationContextAwa
|
||||
}
|
||||
return validFor;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean adjustAttachment(NodeRef nodeRef, String mimeType, boolean attachmentIn)
|
||||
{
|
||||
boolean attachment = true;
|
||||
if (! attachmentIn)
|
||||
{
|
||||
if ((nonAttachContentTypes != null) && (nonAttachContentTypes.contains(mimeType)))
|
||||
{
|
||||
attachment = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.warn("Ignored attachment=false for " + nodeRef.getId() + " since " + mimeType + " is not in the whitelist for non-attach content types");
|
||||
}
|
||||
}
|
||||
return attachment;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
@@ -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);
|
||||
|
@@ -164,6 +164,9 @@
|
||||
<property name="systemWideDirectUrlConfig" >
|
||||
<ref bean="systemWideDirectUrlConfig" />
|
||||
</property>
|
||||
<property name="nonAttachContentTypes">
|
||||
<value>${content.nonAttach.mimetypes}</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="contentService" parent="baseContentService">
|
||||
|
@@ -3,7 +3,7 @@
|
||||
repository.name=Main Repository
|
||||
|
||||
# Schema number
|
||||
version.schema=15002
|
||||
version.schema=15100
|
||||
|
||||
# Directory configuration
|
||||
|
||||
@@ -1308,3 +1308,6 @@ system.tempFileCleaner.maxTimeToRun=
|
||||
|
||||
# Property to long running migration to remove alf_server in v7+ patch.db-V7.1.0-remove-alf_server-table
|
||||
system.remove-alf_server-table-from-db.ignored=true
|
||||
|
||||
# pre-configured allow list of media/mime types to allow inline instead of attachment (via Content-Disposition response header)
|
||||
content.nonAttach.mimetypes=application/pdf,image/jpeg,image/gif,image/png,image/tiff,image/bmp
|
||||
|
@@ -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,
|
||||
|
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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))
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1 @@
|
||||
mycustommessages.key1=This is a custom message
|
@@ -0,0 +1 @@
|
||||
mycustommessages.key1=Dies ist eine benutzerdefinierte Nachricht
|
@@ -0,0 +1 @@
|
||||
mycustommessages.key1=Ceci est un message personnalis\u00e9
|
Reference in New Issue
Block a user