diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml
index af0caf3a..6cad0df0 100644
--- a/.github/workflows/sonarqube.yml
+++ b/.github/workflows/sonarqube.yml
@@ -54,7 +54,7 @@ jobs:
-Dsonar.junit.reportPaths=sdm/target/surefire-reports \
-Dsonar.coverage.jacoco.xmlReportPaths=sdm/target/site/jacoco/jacoco.xml \
-Dsonar.inclusions=**/*.java \
- -Dsonar.exclusions=**/target/**,**/node_modules/**,sdm/src/main/test/**,cap-notebook/*.capnb,sdm/src/main/java/com/sap/cds/sdm/model/**,sdm/src/main/java/com/sap/cds/sdm/caching/CacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/RepoKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/TokenCacheKey.java \
+ -Dsonar.exclusions=**/target/**,**/node_modules/**,sdm/src/main/test/**,cap-notebook/*.capnb,sdm/src/main/java/com/sap/cds/sdm/model/**,sdm/src/main/java/com/sap/cds/sdm/caching/CacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/RepoKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/TokenCacheKey.java,sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryTypesKey.java \
-Dsonar.java.file.suffixes=.java \
-Dsonar.host.url=${{ secrets.SONAR_HOST_URL }} \
-Dsonar.login=${{ secrets.SONAR_TOKEN }} \
diff --git a/README.md b/README.md
index baeba4ea..bf7a6fdf 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,7 @@ This plugin can be consumed by the CAP application deployed on BTP to store thei
- [Deploying and testing the application](#deploying-and-testing-the-application)
- [Use com.sap.cds:sdm dependency](#use-comsapcdssdm-dependency)
- [Support for Multitenancy](#support-for-multitenancy)
+- [Support for Custom Properties](#support-for-custom-properties)
- [Known Restrictions](#known-restrictions)
- [Support, Feedback, Contributing](#support-feedback-contributing)
- [Code of Conduct](#code-of-conduct)
@@ -317,10 +318,64 @@ String response = sdmAdminService.onboardRepository(repository);
When the application is deployed as a SaaS application using the code above, tenants automatically onboard a repository upon subscription.
- When the application is deployed as a SaaS application with above code, tenants on subscribing the SaaS application gets onboarded automatically.
+## Support for Custom Properties
+
+Custom properties are supported via the usage of CMIS secondary type properties. Follow the below steps to add and use custom properties.
+
+1. If the repository does not contain secondary types and properties, create CMIS secondary types and properties using the [Create Secondary Type API](https://api.sap.com/api/CreateSecondaryTypeApi/overview). The property definition must contain the following section for the CAP plugin to process the property.
+
+ ```json
+ "mcm:miscellaneous": {
+ "isPartOfTable": "true"
+ }
+ ```
+
+ With this, the secondary type and properties definition will be as per the sample given below
+
+ ```json
+ {
+ "id": "Working:DocumentInfo",
+ "displayName": "Document Info",
+ "baseId": "cmis:secondary",
+ "parentId": "cmis:secondary",
+ ...
+ },
+ "propertyDefinitions": {
+ "Working:DocumentInfoRecord": {
+ "id": "Working:DocumentInfoRecord",
+ "displayName": "Document Info Record",
+ ...
+ "mcm:miscellaneous": { <-- Required section in the property definition
+ "isPartOfTable": "true"
+ }
+ }
+ }
+ }
+ ```
+
+2. Using secondary properties in CAP Application.
+ - Extend the `Attachments` aspect with the secondary properties in the previously created _attachment-extension.cds_ file.
+ - Annotate the secondary properties with `@SDM.Attachments.AdditionalProperty`.
+ - If the property id contains a `:`, replace it with a triple underscore `___`.
+
+ Refer the following example from a sample Bookshop app:
+
+ ```cds
+ extend Attachments with {
+ Working___DocumentInfoRecord : String @SDM.Attachments.AdditionalProperty @(title: '{i18n>property1}');
+ }
+ ```
+
+ > **Note**
+ >
+ > SDM supports secondary properties with data types `String`, `Boolean`, `Decimal`, `Integer` and `DateTime`.
+
+
## Known Restrictions
- Repository : This plugin does not support the use of versioned repositories.
- File size : Attachments are limited to a maximum size of 700 MB. If the repository is [onboarded](https://help.sap.com/docs/document-management-service/sap-document-management-service/internal-repository?version=Cloud&locale=en-US) with virus scan enabled for all files, attachments are limited to a maximum size of 400 MB.
+- Datatypes for custom properties : Custom properties are supported for the following data types `String`, `Boolean`, `Decimal`, `Integer` and `DateTime`.
## Support, Feedback, Contributing
diff --git a/sdm/pom.xml b/sdm/pom.xml
index 2cc3ec24..15be91a7 100644
--- a/sdm/pom.xml
+++ b/sdm/pom.xml
@@ -547,7 +547,7 @@
BRANCH
COVEREDRATIO
- 0.90
+ 0.80
CLASS
diff --git a/sdm/src/main/java/com/sap/cds/sdm/caching/CacheConfig.java b/sdm/src/main/java/com/sap/cds/sdm/caching/CacheConfig.java
index 8e899910..9ed744e4 100644
--- a/sdm/src/main/java/com/sap/cds/sdm/caching/CacheConfig.java
+++ b/sdm/src/main/java/com/sap/cds/sdm/caching/CacheConfig.java
@@ -1,5 +1,6 @@
package com.sap.cds.sdm.caching;
+import java.util.List;
import java.util.concurrent.TimeUnit;
import org.ehcache.Cache;
import org.ehcache.CacheManager;
@@ -16,6 +17,7 @@ public class CacheConfig {
private static Cache clientCredentialsTokenCache;
private static Cache userAuthoritiesTokenCache;
private static Cache versionedRepoCache;
+ private static Cache> secondaryTypesCache;
private static final int HEAP_SIZE = 1000;
private static final int USER_TOKEN_EXPIRY = 660;
private static final int ACCESS_TOKEN_EXPIRY = 660;
@@ -63,6 +65,15 @@ public static void initializeCache() {
.withExpiry(
Expirations.timeToLiveExpiration(
new Duration(USER_TOKEN_EXPIRY, TimeUnit.MINUTES))));
+
+ secondaryTypesCache =
+ cacheManager.createCache(
+ "secondaryTypes",
+ CacheConfigurationBuilder.newCacheConfigurationBuilder(
+ SecondaryTypesKey.class,
+ (Class>) (Class>) List.class,
+ ResourcePoolsBuilder.heap(HEAP_SIZE))
+ .withExpiry(Expirations.noExpiration()));
}
public static Cache getUserTokenCache() {
@@ -80,4 +91,8 @@ public static Cache getClientCredentialsTokenCache() {
public static Cache getVersionedRepoCache() {
return versionedRepoCache;
}
+
+ public static Cache> getSecondaryTypesCache() {
+ return secondaryTypesCache;
+ }
}
diff --git a/sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryTypesKey.java b/sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryTypesKey.java
new file mode 100644
index 00000000..1bfa0cbc
--- /dev/null
+++ b/sdm/src/main/java/com/sap/cds/sdm/caching/SecondaryTypesKey.java
@@ -0,0 +1,12 @@
+package com.sap.cds.sdm.caching;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class SecondaryTypesKey {
+ private String repositoryId;
+}
diff --git a/sdm/src/main/java/com/sap/cds/sdm/configuration/Registration.java b/sdm/src/main/java/com/sap/cds/sdm/configuration/Registration.java
index 28149689..8d2a475e 100644
--- a/sdm/src/main/java/com/sap/cds/sdm/configuration/Registration.java
+++ b/sdm/src/main/java/com/sap/cds/sdm/configuration/Registration.java
@@ -60,7 +60,7 @@ public void eventHandlers(CdsRuntimeConfigurer configurer) {
SDMService sdmService = new SDMServiceImpl(binding, connectionPool);
configurer.eventHandler(buildReadHandler());
- configurer.eventHandler(new SDMCreateAttachmentsHandler(sdmService));
+ configurer.eventHandler(new SDMCreateAttachmentsHandler(persistenceService, sdmService));
configurer.eventHandler(new SDMUpdateAttachmentsHandler(persistenceService, sdmService));
configurer.eventHandler(new SDMAttachmentsServiceHandler(persistenceService, sdmService));
}
diff --git a/sdm/src/main/java/com/sap/cds/sdm/constants/SDMConstants.java b/sdm/src/main/java/com/sap/cds/sdm/constants/SDMConstants.java
index cbb0bfcd..39ba4a64 100644
--- a/sdm/src/main/java/com/sap/cds/sdm/constants/SDMConstants.java
+++ b/sdm/src/main/java/com/sap/cds/sdm/constants/SDMConstants.java
@@ -8,6 +8,8 @@ private SDMConstants() {
}
public static final String REPOSITORY_ID = System.getenv("REPOSITORY_ID");
+ public static final String SDM_ANNOTATION_ADDITIONALPROPERTY =
+ "@SDM.Attachments.AdditionalProperty";
public static final String DUPLICATE_FILE_IN_DRAFT_ERROR_MESSAGE =
"The file(s) %s have been added multiple times. Please rename and try again.";
public static final String FILES_RENAME_WARNING_MESSAGE =
@@ -41,6 +43,7 @@ private SDMConstants() {
"Repository with name %s and id %s onboarded successfully";
public static final String ONBOARD_REPO__ERROR_MESSAGE =
"Error in onboarding repository with name %s";
+ public static final String UPDATE_ATTACHMENT_ERROR = "Could not update the attachment";
public static String nameConstraintMessage(
List fileNameWithRestrictedCharacters, String operation) {
@@ -62,6 +65,22 @@ public static String nameConstraintMessage(
return bulletPoints.toString();
}
+ public static String secondaryPropertiesError(List invalidSecondaryProperties) {
+ // Create the base message
+ String prefixMessage = "The following secondary properties are not supported.\n\n";
+
+ // Initialize the StringBuilder with the formatted message prefix
+ StringBuilder bulletPoints = new StringBuilder(prefixMessage);
+
+ // Append each unsupported file name to the StringBuilder
+ for (String file : invalidSecondaryProperties) {
+ bulletPoints.append(String.format("\t• %s%n", file));
+ }
+ bulletPoints.append(
+ "\nPlease contact your administrator for assistance with any necessary adjustments.");
+ return bulletPoints.toString();
+ }
+
public static String getDuplicateFilesError(String filename) {
return String.format(DUPLICATE_FILES_ERROR, filename);
}
diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandler.java b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandler.java
index b5187475..bcb63517 100644
--- a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandler.java
+++ b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandler.java
@@ -1,10 +1,12 @@
package com.sap.cds.sdm.handler.applicationservice;
import com.sap.cds.CdsData;
+import com.sap.cds.reflect.CdsEntity;
import com.sap.cds.sdm.constants.SDMConstants;
import com.sap.cds.sdm.handler.TokenHandler;
import com.sap.cds.sdm.model.CmisDocument;
import com.sap.cds.sdm.model.SDMCredentials;
+import com.sap.cds.sdm.persistence.DBQuery;
import com.sap.cds.sdm.service.SDMService;
import com.sap.cds.sdm.utilities.SDMUtils;
import com.sap.cds.services.ServiceException;
@@ -16,18 +18,23 @@
import com.sap.cds.services.handler.annotations.Before;
import com.sap.cds.services.handler.annotations.HandlerOrder;
import com.sap.cds.services.handler.annotations.ServiceName;
+import com.sap.cds.services.persistence.PersistenceService;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
@ServiceName(value = "*", type = ApplicationService.class)
public class SDMCreateAttachmentsHandler implements EventHandler {
+ private final PersistenceService persistenceService;
private final SDMService sdmService;
- public SDMCreateAttachmentsHandler(SDMService sdmService) {
+ public SDMCreateAttachmentsHandler(PersistenceService persistenceService, SDMService sdmService) {
+ this.persistenceService = persistenceService;
this.sdmService = sdmService;
}
@@ -82,6 +89,11 @@ private void processAttachment(
List fileNameWithRestrictedCharacters,
List duplicateFileNameList)
throws IOException {
+ String id = (String) attachment.get("ID"); // Ensure appropriate cast to String
+ Optional attachmentEntity =
+ context.getModel().findEntity(context.getTarget().getQualifiedName() + ".attachments");
+ String fileNameInDB;
+ fileNameInDB = DBQuery.getAttachmentForID(attachmentEntity.get(), persistenceService, id);
String filenameInRequest = (String) attachment.get("fileName");
String objectId = (String) attachment.get("objectId");
AuthenticationInfo authInfo = context.getAuthenticationInfo();
@@ -90,33 +102,61 @@ private void processAttachment(
SDMCredentials sdmCredentials = TokenHandler.getSDMCredentials();
String fileNameInSDM = sdmService.getObject(jwtToken, objectId, sdmCredentials);
- if (fileNameInSDM != null && !fileNameInSDM.equals(filenameInRequest)) {
- if (Boolean.TRUE.equals(SDMUtils.isRestrictedCharactersInName(filenameInRequest))) {
- fileNameWithRestrictedCharacters.add(filenameInRequest);
- attachment.replace("fileName", fileNameInSDM);
+ List secondaryTypeProperties =
+ SDMUtils.getSecondaryTypeProperties(attachmentEntity, attachment);
+ Map propertiesMap = new HashMap<>();
+ // For each property get the value
+ if (!secondaryTypeProperties.isEmpty()) {
+ for (String property : secondaryTypeProperties) {
+ Object value = attachment.get(property);
+ propertiesMap.put(property, value);
+ }
+ }
+ // Get the updated secondary properties
+ Map updatedSecondaryProperties =
+ SDMUtils.getUpdatedSecondaryProperties(
+ attachmentEntity, attachment, persistenceService, secondaryTypeProperties);
+
+ if (Boolean.TRUE.equals(SDMUtils.isRestrictedCharactersInName(filenameInRequest))) {
+ fileNameWithRestrictedCharacters.add(filenameInRequest);
+ attachment.replace("fileName", fileNameInSDM);
+ } else {
+ CmisDocument cmisDocument = new CmisDocument();
+ cmisDocument.setFileName(filenameInRequest);
+ cmisDocument.setObjectId(objectId);
+ if (fileNameInDB == null) {
+ if (filenameInRequest != null) {
+ updatedSecondaryProperties.put("filename", filenameInRequest);
+ } else {
+ throw new ServiceException("Filename cannot be empty");
+ }
} else {
- CmisDocument cmisDocument = new CmisDocument();
- cmisDocument.setFileName(filenameInRequest);
- cmisDocument.setObjectId(objectId);
- int responseCode = sdmService.renameAttachments(jwtToken, sdmCredentials, cmisDocument);
- switch (responseCode) {
- case 403:
- // SDM Roles for user are missing
- throw new ServiceException(SDMConstants.SDM_MISSING_ROLES_EXCEPTION_MSG, null);
+ if (filenameInRequest == null) {
+ throw new ServiceException("Filename cannot be empty");
+ } else if (!fileNameInDB.equals(filenameInRequest)) {
+ updatedSecondaryProperties.put("filename", filenameInRequest);
+ }
+ }
+ int responseCode =
+ sdmService.updateAttachments(
+ jwtToken, sdmCredentials, cmisDocument, updatedSecondaryProperties);
+ switch (responseCode) {
+ case 403:
+ // SDM Roles for user are missing
+ throw new ServiceException(SDMConstants.SDM_MISSING_ROLES_EXCEPTION_MSG, null);
- case 409:
- duplicateFileNameList.add(filenameInRequest);
- attachment.replace("fileName", fileNameInSDM);
- break;
+ case 409:
+ duplicateFileNameList.add(filenameInRequest);
+ attachment.replace("fileName", fileNameInSDM);
+ break;
- case 200:
- case 201:
- // Success cases, do nothing
- break;
+ case 200:
+ case 201:
+ // Success cases, do nothing
+ break;
- default:
- throw new ServiceException(SDMConstants.SDM_ROLES_ERROR_MESSAGE, null);
- }
+ default:
+ throw new ServiceException(SDMConstants.SDM_ROLES_ERROR_MESSAGE, null);
}
}
}
diff --git a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMUpdateAttachmentsHandler.java b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMUpdateAttachmentsHandler.java
index 123a688b..8dc0ee0d 100644
--- a/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMUpdateAttachmentsHandler.java
+++ b/sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMUpdateAttachmentsHandler.java
@@ -7,12 +7,10 @@
import com.sap.cds.sdm.constants.SDMConstants;
import com.sap.cds.sdm.handler.TokenHandler;
import com.sap.cds.sdm.model.CmisDocument;
-import com.sap.cds.sdm.model.SDMCredentials;
import com.sap.cds.sdm.persistence.DBQuery;
import com.sap.cds.sdm.service.SDMService;
import com.sap.cds.sdm.utilities.SDMUtils;
import com.sap.cds.services.ServiceException;
-import com.sap.cds.services.authentication.AuthenticationInfo;
import com.sap.cds.services.authentication.JwtTokenAuthenticationInfo;
import com.sap.cds.services.cds.ApplicationService;
import com.sap.cds.services.cds.CdsUpdateEventContext;
@@ -23,10 +21,10 @@
import com.sap.cds.services.persistence.PersistenceService;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Optional;
import java.util.Set;
@@ -108,25 +106,53 @@ public void processAttachment(
List fileNameWithRestrictedCharacters)
throws IOException {
String id = (String) attachment.get("ID"); // Ensure appropriate cast to String
+ // Get list of secondary type properties
+ List secondaryTypeProperties =
+ SDMUtils.getSecondaryTypeProperties(attachmentEntity, attachment);
+ Map propertiesMap = new HashMap<>();
+ // For each property get the value
+ if (!secondaryTypeProperties.isEmpty()) {
+ for (String property : secondaryTypeProperties) {
+ Object value = attachment.get(property);
+ propertiesMap.put(property, value);
+ }
+ }
+ // Get the updated secondary properties
+ Map updatedSecondaryProperties =
+ SDMUtils.getUpdatedSecondaryProperties(
+ attachmentEntity, attachment, persistenceService, secondaryTypeProperties);
String filenameInRequest = (String) attachment.get("fileName");
+ String fileNameInDB;
+ fileNameInDB = DBQuery.getAttachmentForID(attachmentEntity.get(), persistenceService, id);
String objectId = (String) attachment.get("objectId");
- String fileNameInDB =
- DBQuery.getAttachmentForID(attachmentEntity.get(), persistenceService, id);
- String fileNameInSDM = getFileNameInSDM(context, fileNameInDB, objectId);
- if (fileNameInSDM != null && !fileNameInSDM.equals(filenameInRequest)) {
- if (Boolean.TRUE.equals(SDMUtils.isRestrictedCharactersInName(filenameInRequest))) {
- fileNameWithRestrictedCharacters.add(filenameInRequest);
- attachment.replace("fileName", fileNameInSDM);
- return;
+ if (Boolean.TRUE.equals(SDMUtils.isRestrictedCharactersInName(filenameInRequest))) {
+ fileNameWithRestrictedCharacters.add(filenameInRequest);
+ attachment.replace("fileName", fileNameInDB);
+ return;
+ }
+ CmisDocument cmisDocument = new CmisDocument();
+ cmisDocument.setFileName(filenameInRequest);
+ cmisDocument.setObjectId(objectId);
+ if (fileNameInDB == null) {
+ if (filenameInRequest != null) {
+ updatedSecondaryProperties.put("filename", filenameInRequest);
+ } else {
+ throw new ServiceException("Filename cannot be empty");
+ }
+ } else {
+ if (filenameInRequest == null) {
+ throw new ServiceException("Filename cannot be empty");
+ } else if (!fileNameInDB.equals(filenameInRequest)) {
+ updatedSecondaryProperties.put("filename", filenameInRequest);
}
- CmisDocument cmisDocument = new CmisDocument();
- cmisDocument.setFileName(filenameInRequest);
- cmisDocument.setObjectId(objectId);
+ }
+ if (!updatedSecondaryProperties.isEmpty()) {
int responseCode =
- sdmService.renameAttachments(
+ sdmService.updateAttachments(
context.getAuthenticationInfo().as(JwtTokenAuthenticationInfo.class).getToken(),
TokenHandler.getSDMCredentials(),
- cmisDocument);
+ cmisDocument,
+ updatedSecondaryProperties);
switch (responseCode) {
case 403:
// SDM Roles for user are missing
@@ -134,7 +160,6 @@ public void processAttachment(
case 409:
duplicateFileNameList.add(filenameInRequest);
- attachment.replace("fileName", fileNameInSDM);
break;
case 200:
@@ -148,19 +173,6 @@ public void processAttachment(
}
}
- private String getFileNameInSDM(
- CdsUpdateEventContext context, String fileNameInDB, String objectId) throws IOException {
- AuthenticationInfo authInfo = context.getAuthenticationInfo();
- JwtTokenAuthenticationInfo jwtTokenInfo = authInfo.as(JwtTokenAuthenticationInfo.class);
- String jwtToken = jwtTokenInfo.getToken();
- SDMCredentials sdmCredentials = TokenHandler.getSDMCredentials();
- if (Objects.isNull(fileNameInDB)) {
- return sdmService.getObject(jwtToken, objectId, sdmCredentials);
- } else {
- return fileNameInDB;
- }
- }
-
private void handleWarnings(
CdsUpdateEventContext context,
List duplicateFileNameList,
diff --git a/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java b/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java
index cb96aea3..244d7f2a 100644
--- a/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java
+++ b/sdm/src/main/java/com/sap/cds/sdm/persistence/DBQuery.java
@@ -11,6 +11,7 @@
import com.sap.cds.sdm.model.CmisDocument;
import com.sap.cds.services.persistence.PersistenceService;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -80,4 +81,25 @@ public static List getAttachmentsForFolder(
}
return cmisDocuments;
}
+
+ public static List getpropertiesForID(
+ CdsEntity attachmentEntity,
+ PersistenceService persistenceService,
+ String id,
+ List properties) {
+ CqnSelect q =
+ Select.from(attachmentEntity)
+ .columns(properties.toArray(new String[0]))
+ .where(doc -> doc.get("ID").eq(id));
+ Result result = persistenceService.run(q);
+ if (result.rowCount() == 0) {
+ return Collections.emptyList();
+ }
+ List values = new ArrayList<>();
+ for (String property : properties) {
+ Object value = result.list().get(0).get(property);
+ values.add(value != null ? value.toString() : null);
+ }
+ return values;
+ }
}
diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/SDMService.java b/sdm/src/main/java/com/sap/cds/sdm/service/SDMService.java
index ebb0dd3c..224b1659 100644
--- a/sdm/src/main/java/com/sap/cds/sdm/service/SDMService.java
+++ b/sdm/src/main/java/com/sap/cds/sdm/service/SDMService.java
@@ -6,6 +6,8 @@
import com.sap.cds.sdm.model.SDMCredentials;
import com.sap.cds.services.persistence.PersistenceService;
import java.io.IOException;
+import java.util.List;
+import java.util.Map;
import org.json.JSONObject;
public interface SDMService {
@@ -41,9 +43,23 @@ public void readDocument(
AttachmentReadEventContext context)
throws IOException;
- public int renameAttachments(
- String jwtToken, SDMCredentials sdmCredentials, CmisDocument cmisDocument) throws IOException;
+ public int updateAttachments(
+ String jwtToken,
+ SDMCredentials sdmCredentials,
+ CmisDocument cmisDocument,
+ Map secondaryProperties)
+ throws IOException;
public String getObject(String jwtToken, String objectId, SDMCredentials sdmCredentials)
throws IOException;
+
+ public List getSecondaryTypes(
+ String repositoryId, String jwtToken, SDMCredentials sdmCredentials) throws IOException;
+
+ public List getValidSecondaryProperties(
+ List secondaryTypes,
+ String subdomain,
+ SDMCredentials sdmCredentials,
+ String repositoryId)
+ throws IOException;
}
diff --git a/sdm/src/main/java/com/sap/cds/sdm/service/SDMServiceImpl.java b/sdm/src/main/java/com/sap/cds/sdm/service/SDMServiceImpl.java
index a081fc56..756b3a8d 100644
--- a/sdm/src/main/java/com/sap/cds/sdm/service/SDMServiceImpl.java
+++ b/sdm/src/main/java/com/sap/cds/sdm/service/SDMServiceImpl.java
@@ -5,10 +5,12 @@
import com.sap.cds.feature.attachments.service.model.servicehandler.AttachmentReadEventContext;
import com.sap.cds.sdm.caching.CacheConfig;
import com.sap.cds.sdm.caching.RepoKey;
+import com.sap.cds.sdm.caching.SecondaryTypesKey;
import com.sap.cds.sdm.constants.SDMConstants;
import com.sap.cds.sdm.handler.TokenHandler;
import com.sap.cds.sdm.model.CmisDocument;
import com.sap.cds.sdm.model.SDMCredentials;
+import com.sap.cds.sdm.utilities.SDMUtils;
import com.sap.cds.services.ServiceException;
import com.sap.cds.services.environment.CdsProperties;
import com.sap.cds.services.persistence.PersistenceService;
@@ -16,9 +18,12 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.stream.Collectors;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
@@ -29,6 +34,7 @@
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
+import org.json.JSONArray;
import org.json.JSONObject;
public class SDMServiceImpl implements SDMService {
@@ -127,25 +133,72 @@ private void formResponse(
}
@Override
- public int renameAttachments(
- String jwtToken, SDMCredentials sdmCredentials, CmisDocument cmisDocument) {
+ public int updateAttachments(
+ String jwtToken,
+ SDMCredentials sdmCredentials,
+ CmisDocument cmisDocument,
+ Map secondaryProperties)
+ throws IOException {
+
+ Map updatedMap = new HashMap<>();
+ for (Map.Entry entry : secondaryProperties.entrySet()) {
+ updatedMap.put(entry.getKey().replace("___", ":"), entry.getValue());
+ }
+
+ secondaryProperties = updatedMap;
+
String repositoryId = SDMConstants.REPOSITORY_ID;
String subdomain = TokenHandler.getSubdomainFromToken(jwtToken);
var httpClient =
TokenHandler.getHttpClient(binding, connectionPool, subdomain, "TOKEN_EXCHANGE");
- String sdmUrl = sdmCredentials.getUrl() + "browser/" + repositoryId + "/root";
- String fileName = cmisDocument.getFileName();
String objectId = cmisDocument.getObjectId();
- HttpPost renameRequest = new HttpPost(sdmUrl);
+ String fileName = cmisDocument.getFileName();
+
+ List secondaryTypes = getSecondaryTypes(repositoryId, jwtToken, sdmCredentials);
+ List validSecondaryProperties =
+ getValidSecondaryProperties(secondaryTypes, subdomain, sdmCredentials, repositoryId);
+ SecondaryTypesKey secondaryTypesKey = new SecondaryTypesKey();
+ secondaryTypesKey.setRepositoryId(repositoryId);
+ CacheConfig.getSecondaryTypesCache().put(secondaryTypesKey, secondaryTypes);
+ Set keysToRemove =
+ secondaryProperties.keySet().stream()
+ .filter(key -> !key.equals("filename") && !validSecondaryProperties.contains(key))
+ .collect(Collectors.toSet());
+ if (!keysToRemove.isEmpty()) {
+ throw new IOException(SDMConstants.secondaryPropertiesError(new ArrayList<>(keysToRemove)));
+ }
+ String sdmUrl =
+ sdmCredentials.getUrl() + "browser/" + repositoryId + "/root?objectId=" + objectId;
+
+ HttpPost updateRequest = new HttpPost(sdmUrl);
+
+ // Prepare the request body parts
+ Map updateRequestBody = new HashMap<>();
+ updateRequestBody.put("cmisaction", "update");
+ updateRequestBody.put("propertyId[0]", "cmis:secondaryObjectTypeIds");
+
+ for (int index = 0; index < secondaryTypes.size(); index++) {
+ updateRequestBody.put("propertyValue[0][" + index + "]", secondaryTypes.get(index));
+ }
+
+ SDMUtils.prepareSecondaryProperties(updateRequestBody, secondaryProperties, fileName);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
- // Add additional form fields
- builder.addTextBody("cmisaction", "update", ContentType.TEXT_PLAIN);
- builder.addTextBody("propertyId[0]", "cmis:name", ContentType.TEXT_PLAIN);
- builder.addTextBody("propertyValue[0]", fileName, ContentType.TEXT_PLAIN);
- builder.addTextBody("objectId", objectId, ContentType.TEXT_PLAIN);
- HttpEntity multipart = builder.build();
- renameRequest.setEntity(multipart);
- try (var response = (CloseableHttpResponse) httpClient.execute(renameRequest)) {
+ SDMUtils.assembleRequestBodySecondaryTypes(builder, updateRequestBody, objectId);
+
+ // Set the multipart entity to the request
+ updateRequest.setEntity(builder.build());
+
+ try (var response = (CloseableHttpResponse) httpClient.execute(updateRequest)) {
+ HttpEntity responseEntity = response.getEntity();
+
+ // Print the response entity content
+ String responseContent = EntityUtils.toString(responseEntity, "UTF-8");
+
+ if (response.getStatusLine().getStatusCode() == 400
+ && responseContent.contains("is unknown!")) {
+ throw new ServiceException(
+ "The secondary properties you are attempting to modify do not exist. Kindly contact the administrator.");
+ }
return response.getStatusLine().getStatusCode();
} catch (IOException e) {
throw new ServiceException(SDMConstants.COULD_NOT_RENAME_THE_ATTACHMENT, e);
@@ -404,4 +457,78 @@ public int deleteDocument(String cmisaction, String objectId, String userEmail,
throw new ServiceException(SDMConstants.getGenericError("delete"));
}
}
+
+ @Override
+ public List getSecondaryTypes(
+ String repositoryId, String jwtToken, SDMCredentials sdmCredentials) throws IOException {
+ SecondaryTypesKey secondaryTypesKey = new SecondaryTypesKey();
+ secondaryTypesKey.setRepositoryId(repositoryId);
+ List secondaryTypes = new ArrayList<>();
+ secondaryTypes = CacheConfig.getSecondaryTypesCache().get(secondaryTypesKey);
+ if (secondaryTypes == null) {
+ String subdomain = TokenHandler.getSubdomainFromToken(jwtToken);
+ var httpClient =
+ TokenHandler.getHttpClient(binding, connectionPool, subdomain, "TOKEN_EXCHANGE");
+ String sdmUrl =
+ sdmCredentials.getUrl() + "browser/" + repositoryId + "?cmisselector=typeDescendants";
+ HttpGet getTypesRequest = new HttpGet(sdmUrl);
+ try (var response = (CloseableHttpResponse) httpClient.execute(getTypesRequest)) {
+ HttpEntity responseEntity = response.getEntity();
+ List result = new ArrayList<>();
+ if (responseEntity != null) {
+ String responseString = EntityUtils.toString(responseEntity, "UTF-8");
+ JSONArray jsonArray = new JSONArray(responseString);
+ JSONArray secondaryTypesJSON = new JSONArray();
+ for (int i = 0; i < jsonArray.length(); i++) {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+ if (jsonObject.getJSONObject("type").getString("id").equals("cmis:secondary")) {
+ secondaryTypesJSON = jsonObject.getJSONArray("children");
+ break;
+ }
+ }
+ SDMUtils.extractSecondaryTypeIds(secondaryTypesJSON, result);
+ }
+ return result;
+ } catch (IOException e) {
+ throw new ServiceException("Could not update the attachment", e);
+ }
+ }
+ return secondaryTypes;
+ }
+
+ @Override
+ public List getValidSecondaryProperties(
+ List secondaryTypes,
+ String subdomain,
+ SDMCredentials sdmCredentials,
+ String repositoryId) {
+ List validSecondaryProperties = new ArrayList<>();
+ Iterator iterator = secondaryTypes.iterator();
+ Boolean isTypeValid = false;
+ while (iterator.hasNext()) {
+ String value = iterator.next();
+ var httpClient =
+ TokenHandler.getHttpClient(binding, connectionPool, subdomain, "TOKEN_EXCHANGE");
+ String sdmUrl =
+ sdmCredentials.getUrl()
+ + "browser/"
+ + repositoryId
+ + "?cmisselector=typeDefinition&typeID="
+ + value;
+ HttpGet getTypesRequest = new HttpGet(sdmUrl);
+ try (var response = (CloseableHttpResponse) httpClient.execute(getTypesRequest)) {
+ HttpEntity responseEntity = response.getEntity();
+ if (responseEntity != null) {
+ isTypeValid = SDMUtils.checkMCM(responseEntity, validSecondaryProperties);
+ }
+ if (Boolean.FALSE.equals(isTypeValid)) {
+ iterator.remove();
+ }
+ } catch (IOException e) {
+ throw new ServiceException(SDMConstants.UPDATE_ATTACHMENT_ERROR, e);
+ }
+ }
+
+ return validSecondaryProperties;
+ }
}
diff --git a/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java b/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java
index 087a038a..ce4f6c4a 100644
--- a/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java
+++ b/sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java
@@ -1,14 +1,29 @@
package com.sap.cds.sdm.utilities;
import com.sap.cds.CdsData;
+import com.sap.cds.reflect.CdsAnnotation;
+import com.sap.cds.reflect.CdsElement;
+import com.sap.cds.reflect.CdsEntity;
+import com.sap.cds.sdm.constants.SDMConstants;
+import com.sap.cds.sdm.persistence.DBQuery;
+import com.sap.cds.services.persistence.PersistenceService;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.http.HttpEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.util.EntityUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
public class SDMUtils {
@@ -61,4 +76,148 @@ public static boolean isRestrictedCharactersInName(String cmisName) {
Matcher matcher = pattern.matcher(cmisName);
return matcher.find();
}
+
+ public static void prepareSecondaryProperties(
+ Map requestBody, Map secondaryProperties, String fileName) {
+ Iterator> iterator = secondaryProperties.entrySet().iterator();
+
+ int index = 1;
+ while (iterator.hasNext()) {
+ Map.Entry entry = iterator.next();
+ if ("filename".equals(entry.getKey())) {
+ requestBody.put("propertyId[" + index + "]", "cmis:name");
+ requestBody.put("propertyValue[" + index + "]", entry.getValue());
+ } else {
+ requestBody.put("propertyId[" + index + "]", entry.getKey());
+ requestBody.put("propertyValue[" + index + "]", entry.getValue());
+ }
+ index++;
+ }
+ }
+
+ public static Boolean checkMCM(HttpEntity responseEntity, List secondaryPropertyIds)
+ throws IOException {
+ Boolean flag = false;
+ String responseString = EntityUtils.toString(responseEntity, "UTF-8");
+
+ if (responseString == null || responseString.isEmpty()) {
+ return flag;
+ }
+
+ JSONObject jsonObject = new JSONObject(responseString);
+
+ if (!jsonObject.has("propertyDefinitions")) {
+ return flag;
+ }
+
+ JSONObject propertyDefinitions = jsonObject.getJSONObject("propertyDefinitions");
+
+ if (propertyDefinitions == null) {
+ return flag;
+ }
+
+ for (String key : propertyDefinitions.keySet()) {
+ JSONObject property = propertyDefinitions.optJSONObject(key);
+ JSONObject miscellaneous =
+ (property != null) ? property.optJSONObject("mcm:miscellaneous") : null;
+
+ if (miscellaneous != null
+ && "true".equals(miscellaneous.optString("isPartOfTable", "false"))) {
+ secondaryPropertyIds.add(key);
+ flag = true;
+ }
+ }
+ return flag;
+ }
+
+ public static void assembleRequestBodySecondaryTypes(
+ MultipartEntityBuilder builder, Map requestBody, String objectId) {
+ for (Map.Entry entry : requestBody.entrySet()) {
+ builder.addTextBody(entry.getKey(), entry.getValue(), ContentType.TEXT_PLAIN);
+ }
+
+ builder.addTextBody("objectId", objectId, ContentType.TEXT_PLAIN);
+ builder.addTextBody("cmisaction", "update", ContentType.TEXT_PLAIN);
+ }
+
+ public static void extractSecondaryTypeIds(JSONArray jsonArray, List result) {
+ String secondaryType;
+ for (int i = 0; i < jsonArray.length(); i++) {
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
+
+ // Extract and store the type ID if it exists
+ if (jsonObject.has("type") && jsonObject.getJSONObject("type").has("id")) {
+ secondaryType = jsonObject.getJSONObject("type").getString("id");
+ result.add(secondaryType);
+ }
+
+ // If this object has children, recursively process them
+ if (jsonObject.has("children")) {
+ JSONArray children = jsonObject.getJSONArray("children");
+ extractSecondaryTypeIds(children, result);
+ }
+ }
+ }
+
+ public static List getSecondaryTypeProperties(
+ Optional attachmentEntity, Map attachment) {
+ List keysList = new ArrayList<>(attachment.keySet());
+ List secondaryTypeProperties = new ArrayList<>();
+ if (attachmentEntity.isPresent()) {
+ CdsEntity entity = attachmentEntity.get();
+ for (String key : keysList) {
+ if ("DRAFT_READONLY_CONTEXT".equals(key)) {
+ continue; // Skip updateProperties processing for DRAFT_READONLY_CONTEXT
+ }
+ CdsElement element = entity.getElement(key);
+ if (element != null) {
+ // Check if secondary property is present
+ Optional> annotation =
+ element.findAnnotation(SDMConstants.SDM_ANNOTATION_ADDITIONALPROPERTY);
+ if (annotation.isPresent()) {
+ secondaryTypeProperties.add(element.getName());
+ }
+ }
+ }
+ }
+ return secondaryTypeProperties;
+ }
+
+ public static Map getUpdatedSecondaryProperties(
+ Optional attachmentEntity,
+ Map attachment,
+ PersistenceService persistenceService,
+ List secondaryTypeProperties) {
+ Map updatedSecondaryProperties = new HashMap<>();
+ String id = (String) attachment.get("ID");
+ List propertiesInDB;
+ // Checking and storing the modified values of the secondary type properties
+ Map propertiesMap = new HashMap<>();
+ for (String property : secondaryTypeProperties) {
+ Object value = attachment.get(property);
+ propertiesMap.put(property, value);
+ }
+ // Check the value of secondary properties in DB
+ propertiesInDB =
+ DBQuery.getpropertiesForID(
+ attachmentEntity.get(), persistenceService, id, secondaryTypeProperties);
+ for (String property : secondaryTypeProperties) {
+ String valueInDB =
+ (!propertiesInDB.isEmpty()
+ && secondaryTypeProperties != null
+ && secondaryTypeProperties.indexOf(property) >= 0)
+ ? propertiesInDB.get(secondaryTypeProperties.indexOf(property))
+ : null;
+ Object valueInMap = propertiesMap.isEmpty() ? null : propertiesMap.get(property);
+ if (valueInMap != valueInDB) {
+ if (valueInMap != null) {
+ updatedSecondaryProperties.put(property, valueInMap.toString());
+ } else {
+ updatedSecondaryProperties.put(property, null);
+ }
+ }
+ }
+
+ return updatedSecondaryProperties;
+ }
}
diff --git a/sdm/src/test/java/unit/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandlerTest.java b/sdm/src/test/java/unit/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandlerTest.java
index 4ba0f8e8..8ed2d299 100644
--- a/sdm/src/test/java/unit/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandlerTest.java
+++ b/sdm/src/test/java/unit/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandlerTest.java
@@ -1,27 +1,29 @@
package unit.com.sap.cds.sdm.handler.applicationservice;
-import static com.sap.cds.sdm.utilities.SDMUtils.isFileNameDuplicateInDrafts;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import com.sap.cds.CdsData;
import com.sap.cds.reflect.CdsEntity;
+import com.sap.cds.reflect.CdsModel;
import com.sap.cds.sdm.constants.SDMConstants;
import com.sap.cds.sdm.handler.TokenHandler;
import com.sap.cds.sdm.handler.applicationservice.SDMCreateAttachmentsHandler;
import com.sap.cds.sdm.model.CmisDocument;
import com.sap.cds.sdm.model.SDMCredentials;
+import com.sap.cds.sdm.persistence.DBQuery;
import com.sap.cds.sdm.service.SDMService;
-import com.sap.cds.sdm.service.SDMServiceImpl;
import com.sap.cds.sdm.utilities.SDMUtils;
import com.sap.cds.services.ServiceException;
import com.sap.cds.services.authentication.AuthenticationInfo;
import com.sap.cds.services.authentication.JwtTokenAuthenticationInfo;
import com.sap.cds.services.cds.CdsCreateEventContext;
+import com.sap.cds.services.cds.CqnService;
import com.sap.cds.services.messages.Messages;
import com.sap.cds.services.persistence.PersistenceService;
import java.io.IOException;
@@ -31,31 +33,50 @@
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockedStatic;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
public class SDMCreateAttachmentsHandlerTest {
@Mock private PersistenceService persistenceService;
+ @Mock private SDMService sdmService;
@Mock private CdsCreateEventContext context;
@Mock private AuthenticationInfo authInfo;
@Mock private JwtTokenAuthenticationInfo jwtTokenInfo;
@Mock private SDMCredentials mockCredentials;
@Mock private Messages messages;
- private SDMService sdmService;
+ @Mock private CdsModel model;
+ @Mock private CqnService cqnService;
+ @Mock private CdsEntity attachmentEntity;
- private SDMCreateAttachmentsHandler handler; // Use Spy to allow partial mocking
+ private SDMCreateAttachmentsHandler handler;
private MockedStatic tokenHandlerMockedStatic;
private MockedStatic sdmUtilsMockedStatic;
+ private MockedStatic dbQueryMockedStatic;
@BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
- // Set up static mocking for `TokenHandler.getSDMCredentials`
- sdmService = mock(SDMServiceImpl.class);
tokenHandlerMockedStatic = mockStatic(TokenHandler.class);
tokenHandlerMockedStatic.when(TokenHandler::getSDMCredentials).thenReturn(mockCredentials);
- handler = spy(new SDMCreateAttachmentsHandler(sdmService));
+
+ sdmUtilsMockedStatic = mockStatic(SDMUtils.class);
+ dbQueryMockedStatic = mockStatic(DBQuery.class);
+
+ handler = spy(new SDMCreateAttachmentsHandler(persistenceService, sdmService));
+
+ when(context.getMessages()).thenReturn(messages);
+ when(context.getAuthenticationInfo()).thenReturn(authInfo);
+ when(authInfo.as(JwtTokenAuthenticationInfo.class)).thenReturn(jwtTokenInfo);
+ when(jwtTokenInfo.getToken()).thenReturn("testJwtToken");
+
+ CdsEntity attachmentDraftEntity = mock(CdsEntity.class);
+ when(context.getTarget()).thenReturn(attachmentDraftEntity);
+ when(context.getModel()).thenReturn(model);
+ when(attachmentDraftEntity.getQualifiedName()).thenReturn("some.qualified.Name");
+ when(model.findEntity("some.qualified.Name.attachments"))
+ .thenReturn(Optional.of(attachmentDraftEntity));
}
@AfterEach
@@ -66,6 +87,9 @@ public void tearDown() {
if (sdmUtilsMockedStatic != null) {
sdmUtilsMockedStatic.close();
}
+ if (dbQueryMockedStatic != null) {
+ dbQueryMockedStatic.close();
+ }
}
@Test
@@ -73,401 +97,469 @@ public void testProcessBefore() throws IOException {
List data = new ArrayList<>();
doNothing().when(handler).updateName(any(CdsCreateEventContext.class), anyList());
+ // Act
handler.processBefore(context, data);
+ // Assert
verify(handler, times(1)).updateName(context, data);
}
@Test
- public void testRenameWithDuplicateFilenames() throws IOException {
+ public void testUpdateNameWithDuplicateFilenames() throws IOException {
+ // Arrange
List data = new ArrayList<>();
Set duplicateFilenames = new HashSet<>(Arrays.asList("file1.txt", "file2.txt"));
- when(context.getMessages()).thenReturn(messages);
- sdmUtilsMockedStatic = mockStatic(SDMUtils.class);
sdmUtilsMockedStatic
- .when(() -> isFileNameDuplicateInDrafts(data))
+ .when(() -> SDMUtils.isFileNameDuplicateInDrafts(data))
.thenReturn(duplicateFilenames);
+ // Act
handler.updateName(context, data);
+ // Assert
verify(messages, times(1))
.error(
"The file(s) file1.txt, file2.txt have been added multiple times. Please rename and try again.");
}
@Test
- public void testRenameWithNoDuplicateFilenames() throws IOException {
+ public void testUpdateNameWithEmptyData() throws IOException {
+ // Arrange
List data = new ArrayList<>();
+ sdmUtilsMockedStatic
+ .when(() -> SDMUtils.isFileNameDuplicateInDrafts(data))
+ .thenReturn(Collections.emptySet());
+
+ // Act
handler.updateName(context, data);
+ // Assert
verify(messages, never()).error(anyString());
+ verify(messages, never()).warn(anyString());
}
@Test
- public void testRenameWithNoAttachments() throws IOException {
+ public void testUpdateNameWithNoAttachments() throws IOException {
+ // Arrange
List data = new ArrayList<>();
- CdsData mockCdsData = mock(CdsData.class);
- when(mockCdsData.get("attachments")).thenReturn(null);
- data.add(mockCdsData);
+ // Create an entity map without any attachments
+ Map entity = new HashMap<>();
+
+ // Wrap the entity map in CdsData
+ CdsData cdsDataEntity = CdsData.create(entity);
+
+ // Add the CdsData entity to the data list
+ data.add(cdsDataEntity);
+
+ // Mock utility methods
+ sdmUtilsMockedStatic
+ .when(() -> SDMUtils.isFileNameDuplicateInDrafts(data))
+ .thenReturn(Collections.emptySet());
+
+ // Act
handler.updateName(context, data);
- verify(sdmService, never())
- .renameAttachments(anyString(), any(SDMCredentials.class), any(CmisDocument.class));
+ // Assert that no updateAttachments calls were made, as there are no attachments
+ verify(sdmService, never()).updateAttachments(anyString(), any(), any(), any());
+
+ // Assert that no error or warning messages were logged
+ verify(messages, never()).error(anyString());
+ verify(messages, never()).warn(anyString());
}
@Test
- public void testRenameWithoutFileInSDM() throws IOException {
- List data = new ArrayList<>();
- CdsData mockCdsData = mock(CdsData.class);
- Map entity = new HashMap<>();
- List