diff --git a/apps/portlet-clouddrives/package-lock.json b/apps/portlet-clouddrives/package-lock.json
index 1dfb303d152..775744306de 100644
--- a/apps/portlet-clouddrives/package-lock.json
+++ b/apps/portlet-clouddrives/package-lock.json
@@ -5224,9 +5224,7 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"dev": true,
- "requires": {
- "ajv": "^8.0.0"
- }
+ "requires": {}
},
"ajv-keywords": {
"version": "5.1.0",
diff --git a/apps/portlet-editors/package-lock.json b/apps/portlet-editors/package-lock.json
index 8cb22084ac1..dfaa3199f75 100644
--- a/apps/portlet-editors/package-lock.json
+++ b/apps/portlet-editors/package-lock.json
@@ -5224,9 +5224,7 @@
"resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
"integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
"dev": true,
- "requires": {
- "ajv": "^8.0.0"
- }
+ "requires": {}
},
"ajv-keywords": {
"version": "5.1.0",
diff --git a/core/connector/pom.xml b/core/connector/pom.xml
index 5b902b90fdb..2dd0e96d3a9 100644
--- a/core/connector/pom.xml
+++ b/core/connector/pom.xml
@@ -12,7 +12,7 @@
eXo PLF:: ECMS Connector
eXo ECMS REST Services
- 0.0
+ 0.10
@@ -204,17 +204,7 @@
org.mockito
- mockito-core
- test
-
-
- org.powermock
- powermock-api-mockito2
- test
-
-
- org.powermock
- powermock-module-junit4
+ mockito-inline
test
diff --git a/core/connector/src/main/java/org/exoplatform/ecm/connector/platform/ManageDocumentService.java b/core/connector/src/main/java/org/exoplatform/ecm/connector/platform/ManageDocumentService.java
index 8cc1c4ee580..8d4f1e918fd 100644
--- a/core/connector/src/main/java/org/exoplatform/ecm/connector/platform/ManageDocumentService.java
+++ b/core/connector/src/main/java/org/exoplatform/ecm/connector/platform/ManageDocumentService.java
@@ -44,6 +44,8 @@
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.apache.commons.lang.StringUtils;
+import org.exoplatform.services.cms.drives.impl.ManageDriveServiceImpl;
+import org.exoplatform.services.jcr.core.ExtendedNode;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -650,10 +652,31 @@ private Element createFileElement(Document document,
return file;
}
+ /**
+ * This function gets or creates the folder where the files will be stored
+ * @param driveName the name of the selected JCR drive
+ * @param workspaceName The name of the JCR workspace
+ * @param currentFolder The folder where the files will be stored
+ * for spaces, the currentFolder will be created directly under the Documents folder of the space.
+ * If the currentFolder param is preceded with 'DRIVE_ROOT_NODE' then currentFolder will be created under the root folder of the space
+ * @return Node object representing the parent folder where the files will be uploaded
+ * @throws Exception
+ */
private Node getNode(String driveName, String workspaceName, String currentFolder) throws Exception {
return getNode(driveName, workspaceName, currentFolder, false);
}
-
+
+ /**
+ * This function gets or creates the folder where the files will be stored
+ * @param driveName the name of the selected JCR drive
+ * @param workspaceName The name of the JCR workspace
+ * @param currentFolder The folder where the files will be stored
+ * for spaces, the currentFolder will be created directly under the Documents folder of the space.
+ * If the currentFolder param is preceded with 'DRIVE_ROOT_NODE' then currentFolder will be created under the root folder of the space
+ * @param isSystem use system session if true
+ * @return Node object representing the parent folder where the files will be uploaded
+ * @throws Exception
+ */
private Node getNode(String driveName, String workspaceName, String currentFolder, boolean isSystem) throws Exception {
Session session;
if (isSystem) {
@@ -661,14 +684,29 @@ private Node getNode(String driveName, String workspaceName, String currentFolde
} else {
session = getSession(workspaceName);
}
- String driveHomePath = manageDriveService.getDriveByName(Text.escapeIllegalJcrChars(driveName)).getHomePath();
+ DriveData driveData = manageDriveService.getDriveByName(Text.escapeIllegalJcrChars(driveName));
+ String driveHomePath = driveData.getHomePath();
String userId = ConversationState.getCurrent().getIdentity().getUserId();
String drivePath = Utils.getPersonalDrivePath(driveHomePath, userId);
Node node = (Node) session.getItem(Text.escapeIllegalJcrChars(drivePath));
if (StringUtils.isEmpty(currentFolder)) {
return node;
}
- for (String folder : currentFolder.split("/")) {
+ // Check if we store the file under Documents folder or under the root folder of the space
+ if(driveName.startsWith(".spaces.") && currentFolder.startsWith("DRIVE_ROOT_NODE")) {
+ String driveRootPath = driveHomePath;
+ if(driveHomePath.contains("/Documents")) {
+ driveRootPath = driveHomePath.substring(0, driveHomePath.indexOf("/Documents"));
+ }
+ // Need system session to create the folder if it does not exist
+ SessionProvider sessionProvider = SessionProvider.createSystemProvider();
+ Session systemSession = sessionProvider.getSession(workspaceName, getCurrentRepository());
+ node = (Node) systemSession.getItem(Text.escapeIllegalJcrChars(driveRootPath));
+ currentFolder = currentFolder.substring("DRIVE_ROOT_NODE/".length());
+ }
+
+ List foldersNames = Arrays.stream(currentFolder.split("/")).filter(item -> !item.isEmpty()).toList().stream().toList();
+ for (String folder : foldersNames) {
String cleanFolderName = org.exoplatform.services.jcr.util.Text.escapeIllegalJcrChars(org.exoplatform.services.cms.impl.Utils.cleanString(folder));
if (node.hasNode(folder)) {
node = node.getNode(folder);
@@ -683,6 +721,16 @@ private Node getNode(String driveName, String workspaceName, String currentFolde
newNode.addMixin(NodetypeConstant.EXO_RSS_ENABLE);
}
newNode.setProperty(NodetypeConstant.EXO_TITLE, org.exoplatform.services.cms.impl.Utils.cleanDocumentTitle(folder));
+
+ // Update permissions
+ if (newNode.canAddMixin("exo:privilegeable")) {
+ newNode.addMixin("exo:privilegeable");
+ }
+ String groupId = driveData.getParameters().get(ManageDriveServiceImpl.DRIVE_PARAMATER_GROUP_ID);
+ if(StringUtils.isNotBlank(groupId) && groupId.startsWith("/spaces/")) {
+ ((ExtendedNode) newNode).setPermission(groupId, new String[]{PermissionType.READ, PermissionType.ADD_NODE, PermissionType.SET_PROPERTY});
+ }
+
node.save();
node = newNode;
}
diff --git a/core/connector/src/test/java/org/exoplatform/BaseConnectorTestSuite.java b/core/connector/src/test/java/org/exoplatform/BaseConnectorTestSuite.java
index 178a9dc1acc..2ead9336724 100644
--- a/core/connector/src/test/java/org/exoplatform/BaseConnectorTestSuite.java
+++ b/core/connector/src/test/java/org/exoplatform/BaseConnectorTestSuite.java
@@ -20,6 +20,7 @@
import org.exoplatform.commons.testing.ConfigTestCase;
//import org.exoplatform.wcm.connector.authoring.TestCopyContentFile;
//import org.exoplatform.wcm.connector.authoring.TestLifecycleConnector;
+import org.exoplatform.ecm.connector.platform.ManageDocumentServiceTest;
import org.exoplatform.wcm.connector.collaboration.TestDownloadConnector;
import org.exoplatform.wcm.connector.collaboration.TestFavoriteRESTService;
import org.exoplatform.wcm.connector.collaboration.TestOpenInOfficeConnector;
@@ -47,7 +48,8 @@
TestDownloadConnector.class,
TestOpenInOfficeConnector.class,
TestThumbnailRESTService.class,
- TestFavoriteRESTService.class
+ TestFavoriteRESTService.class,
+ ManageDocumentServiceTest.class
})
@ConfigTestCase(BaseConnectorTestCase.class)
public class BaseConnectorTestSuite extends BaseExoContainerTestSuite {
diff --git a/core/connector/src/test/java/org/exoplatform/ecm/connector/platform/ManageDocumentServiceTest.java b/core/connector/src/test/java/org/exoplatform/ecm/connector/platform/ManageDocumentServiceTest.java
index f91cf4d6949..f2911be8fda 100644
--- a/core/connector/src/test/java/org/exoplatform/ecm/connector/platform/ManageDocumentServiceTest.java
+++ b/core/connector/src/test/java/org/exoplatform/ecm/connector/platform/ManageDocumentServiceTest.java
@@ -19,10 +19,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.powermock.api.mockito.PowerMockito;
-import org.powermock.core.classloader.annotations.PowerMockIgnore;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
+import org.mockito.MockedStatic;
+import org.mockito.junit.MockitoJUnitRunner;
import javax.jcr.Node;
import javax.jcr.Session;
@@ -30,12 +28,9 @@
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.powermock.api.mockito.PowerMockito.mock;
-import static org.powermock.api.mockito.PowerMockito.when;
+import static org.mockito.Mockito.*;
-@RunWith(PowerMockRunner.class)
-@PowerMockIgnore({ "javax.management.*" })
-@PrepareForTest({ WCMCoreUtils.class, ConversationState.class, Utils.class})
+@RunWith(MockitoJUnitRunner.class)
public class ManageDocumentServiceTest {
@Mock
@@ -58,9 +53,12 @@ public class ManageDocumentServiceTest {
private ManageDocumentService manageDocumentService;
+ MockedStatic UTILS;
+ MockedStatic SESSION_PROVIDER;
+
@Before
public void setUp() throws Exception {
- PowerMockito.mockStatic(WCMCoreUtils.class);
+ MockedStatic WCM_CORE_UTILS = mockStatic(WCMCoreUtils.class);
ValueParam valueParam = mock(ValueParam.class);
when(valueParam.getValue()).thenReturn("20");
when(initParams.getValueParam("upload.limit.size")).thenReturn(valueParam);
@@ -68,21 +66,33 @@ public void setUp() throws Exception {
SessionProvider userSessionProvider = mock(SessionProvider.class);
SessionProvider systemSessionProvider = mock(SessionProvider.class);
- when(WCMCoreUtils.getUserSessionProvider()).thenReturn(userSessionProvider);
- when(WCMCoreUtils.getSystemSessionProvider()).thenReturn(systemSessionProvider);
+ WCM_CORE_UTILS.when(WCMCoreUtils::getUserSessionProvider).thenReturn(userSessionProvider);
+ WCM_CORE_UTILS.when(WCMCoreUtils::getSystemSessionProvider).thenReturn(systemSessionProvider);
RepositoryService repositoryService = mock(RepositoryService.class);
- when(WCMCoreUtils.getService(RepositoryService.class)).thenReturn(repositoryService);
+ WCM_CORE_UTILS.when(() -> WCMCoreUtils.getService(RepositoryService.class)).thenReturn(repositoryService);
ManageableRepository manageableRepository = mock(ManageableRepository.class);
when(repositoryService.getCurrentRepository()).thenReturn(manageableRepository);
- when(systemSessionProvider.getSession("collaboration", manageableRepository)).thenReturn(session);
+ lenient().when(systemSessionProvider.getSession("collaboration", manageableRepository)).thenReturn(session);
when(userSessionProvider.getSession("collaboration", manageableRepository)).thenReturn(session);
- PowerMockito.mockStatic(ConversationState.class);
+ MockedStatic CONVERSATION_STATE = mockStatic(ConversationState.class);
ConversationState conversationState = mock(ConversationState.class);
- when(ConversationState.getCurrent()).thenReturn(conversationState);
+ CONVERSATION_STATE.when(ConversationState::getCurrent).thenReturn(conversationState);
Identity identity = mock(Identity.class);
when(conversationState.getIdentity()).thenReturn(identity);
when(identity.getUserId()).thenReturn("user");
- PowerMockito.mockStatic(Utils.class);
+ DriveData driveData = mock(DriveData.class);
+ when(manageDriveService.getDriveByName(anyString())).thenReturn(driveData);
+ when(driveData.getHomePath()).thenReturn("path");
+ UTILS = mockStatic(Utils.class);
+ UTILS.when(() -> Utils.getPersonalDrivePath("path", "user")).thenReturn("personalDrivePath");
+ UTILS.when(() -> Utils.cleanString(anyString())).thenCallRealMethod();
+ UTILS.when(() -> Utils.cleanName(anyString())).thenCallRealMethod();
+ UTILS.when(() -> Utils.cleanName(anyString(), anyString())).thenCallRealMethod();
+ UTILS.when(() -> Utils.cleanNameWithAccents(anyString())).thenCallRealMethod();
+ UTILS.when(() -> Utils.replaceSpecialChars(anyString(), anyString())).thenCallRealMethod();
+ UTILS.when(() -> Utils.replaceSpecialChars(anyString(), anyString(), anyString())).thenCallRealMethod();
+ SESSION_PROVIDER = mockStatic(SessionProvider.class);
+ SESSION_PROVIDER.when(SessionProvider::createSystemProvider).thenReturn(systemSessionProvider);
}
@Test
@@ -96,19 +106,21 @@ public void checkFileExistence() throws Exception {
response = this.manageDocumentService.checkFileExistence("collaboration", "testspace", "/documents", null);
assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatus());
- response = this.manageDocumentService.checkFileExistence("collaboration", "testspace", "/documents", "test.docx");
- DriveData driveData = mock(DriveData.class);
- when(manageDriveService.getDriveByName(anyString())).thenReturn(driveData);
- when(driveData.getHomePath()).thenReturn("path");
- when(Utils.getPersonalDrivePath("path", "user")).thenReturn("personalDrivePath");
Node node = mock(Node.class);
- when(session.getItem("personalDrivePath")).thenReturn(node);
- when(node.hasNode("Documents")).thenReturn(true);
+ when(session.getItem(anyString())).thenReturn(node);
+ lenient().when(node.hasNode("Documents")).thenReturn(true);
Node targetNode = mock(Node.class);
- when(node.getNode("Documents")).thenReturn(targetNode);
- when(node.isNodeType(NodetypeConstant.EXO_SYMLINK)).thenReturn(false);
- when(fileUploadHandler.checkExistence(targetNode, "test.docx")).thenReturn(Response.ok().build());
+ lenient().when(node.getNode("Documents")).thenReturn(targetNode);
+ lenient().when(node.isNodeType(NodetypeConstant.EXO_SYMLINK)).thenReturn(false);
+ Node folderNode1 = mock(Node.class);
+ when(node.addNode(anyString(), eq(NodetypeConstant.NT_FOLDER))).thenReturn(folderNode1);
+ lenient().when(fileUploadHandler.checkExistence(targetNode, "test.docx")).thenReturn(Response.ok().build());
+
+ response = this.manageDocumentService.checkFileExistence("collaboration", "testspace", "/documents", "test.docx");
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+
+ response = this.manageDocumentService.checkFileExistence("collaboration", ".spaces.space_one", "DRIVE_ROOT_NODE/Documents", "test.docx");
+ assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
}
}
diff --git a/core/services/src/main/java/org/exoplatform/services/cms/drives/impl/ManageDriveServiceImpl.java b/core/services/src/main/java/org/exoplatform/services/cms/drives/impl/ManageDriveServiceImpl.java
index e583dc209fc..844f0cc853e 100644
--- a/core/services/src/main/java/org/exoplatform/services/cms/drives/impl/ManageDriveServiceImpl.java
+++ b/core/services/src/main/java/org/exoplatform/services/cms/drives/impl/ManageDriveServiceImpl.java
@@ -332,7 +332,7 @@ public DriveData getDriveByName(String name) throws Exception{
DriveData drive = groupDriveTemplate.clone();
drive.setHomePath(groupDriveTemplate.getHomePath().replace("${groupId}", groupName));
drive.setName(name);
- drive.getParameters().put(ManageDriveServiceImpl.DRIVE_PARAMATER_GROUP_ID, name);
+ drive.getParameters().put(ManageDriveServiceImpl.DRIVE_PARAMATER_GROUP_ID, groupName);
drive.setPermissions("*:" + groupName);
return drive;
}
diff --git a/core/services/src/main/java/org/exoplatform/services/cms/impl/Utils.java b/core/services/src/main/java/org/exoplatform/services/cms/impl/Utils.java
index 6cfe1806a4c..d2bb10d9f3f 100644
--- a/core/services/src/main/java/org/exoplatform/services/cms/impl/Utils.java
+++ b/core/services/src/main/java/org/exoplatform/services/cms/impl/Utils.java
@@ -704,7 +704,7 @@ public static String cleanDocumentTitle(String title) {
return replaceSpecialChars(title, "[<\\>:\"/|?*]");
}
- private static String replaceSpecialChars(String name, String specialChars) {
+ public static String replaceSpecialChars(String name, String specialChars) {
return replaceSpecialChars(name, specialChars, NodetypeConstant.NT_FILE);
}
public static String replaceSpecialChars(String name, String specialChars, String nodeType) {