Skip to content

Commit 37d5f89

Browse files
authored
Merge branch 'develop' into revertDisableUploadBtn
2 parents d6760c2 + 5982a24 commit 37d5f89

9 files changed

Lines changed: 140 additions & 18 deletions

File tree

sdm/src/main/java/com/sap/cds/sdm/constants/SDMErrorMessages.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ private SDMErrorMessages() {
147147
"Failed to access SDM error key fields";
148148
public static final String FAILED_TO_ACCESS_ERROR_MESSAGES_FIELDS =
149149
"Failed to access SDM error messages fields";
150+
public static final String FILE_EXTENSION_CHANGE_NOT_ALLOWED =
151+
"Changing the file extension is not allowed. The file \"%s\" must retain its original extension \"%s\".";
150152

151153
// Helper Methods to create error/warning messages
152154
public static String buildErrorMessage(

sdm/src/main/java/com/sap/cds/sdm/constants/SDMUIErrorKeys.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ private SDMUIErrorKeys() {}
6868
"SDM.multipleDuplicateFilenamesPrefix";
6969
public static final String MULTIPLE_DUPLICATE_FILENAMES_SUFFIX_KEY =
7070
"SDM.multipleDuplicateFilenamesSuffix";
71+
public static final String FILE_EXTENSION_CHANGE_NOT_ALLOWED_KEY =
72+
"SDM.fileExtensionChangeNotAllowed";
7173

7274
// Update Operation Errors
7375
public static final String FILE_NOT_FOUND_PREFIX_KEY = "SDM.fileNotFoundPrefix";

sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMCreateAttachmentsHandler.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -482,8 +482,22 @@ private void updateAndSendToSDM(
482482
AttachmentsHandlerUtils.prepareCmisDocument(
483483
filenameInRequest, descriptionInRequest, objectId);
484484

485+
List<String> extensionChangedFiles = new ArrayList<>();
485486
AttachmentsHandlerUtils.updateFilenameProperty(
486-
fileNameInDB, filenameInRequest, fileNameInSDM, updatedSecondaryProperties);
487+
fileNameInDB,
488+
filenameInRequest,
489+
fileNameInSDM,
490+
updatedSecondaryProperties,
491+
extensionChangedFiles);
492+
493+
// If extension change was detected, revert filename to original and warn
494+
if (!extensionChangedFiles.isEmpty()) {
495+
attachment.put("fileName", fileNameInSDM);
496+
for (String warningMessage : extensionChangedFiles) {
497+
context.getMessages().warn(warningMessage);
498+
}
499+
}
500+
487501
AttachmentsHandlerUtils.updateDescriptionProperty(
488502
descriptionInSDM,
489503
descriptionInRequest,

sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/SDMUpdateAttachmentsHandler.java

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ private void renameDocument(
197197
List<String> fileNameWithRestrictedCharacters = new ArrayList<>();
198198
List<String> filesNotFound = new ArrayList<>();
199199
List<String> filesWithUnsupportedProperties = new ArrayList<>();
200+
List<String> extensionChangedFiles = new ArrayList<>();
200201
Map<String, String> badRequest = new HashMap<>();
201202
Map<String, String> propertyTitles = new HashMap<>();
202203
List<String> noSDMRoles = new ArrayList<>();
@@ -229,7 +230,8 @@ private void renameDocument(
229230
filesWithUnsupportedProperties,
230231
badRequest,
231232
secondaryPropertiesWithInvalidDefinitions,
232-
noSDMRoles);
233+
noSDMRoles,
234+
extensionChangedFiles);
233235
}
234236
}
235237
handleWarnings(
@@ -241,6 +243,7 @@ private void renameDocument(
241243
badRequest,
242244
propertyTitles,
243245
noSDMRoles,
246+
extensionChangedFiles,
244247
contextInfo);
245248
}
246249

@@ -254,7 +257,8 @@ private void processAttachments(
254257
List<String> filesWithUnsupportedProperties,
255258
Map<String, String> badRequest,
256259
Map<String, String> secondaryPropertiesWithInvalidDefinitions,
257-
List<String> noSDMRoles)
260+
List<String> noSDMRoles,
261+
List<String> extensionChangedFiles)
258262
throws IOException {
259263
logger.debug("Processing {} attachments for update", attachments.size());
260264
List<String> scanFailedFiles = new ArrayList<>();
@@ -275,7 +279,8 @@ private void processAttachments(
275279
secondaryPropertiesWithInvalidDefinitions,
276280
noSDMRoles,
277281
scanFailedFiles,
278-
uploadInProgressFiles);
282+
uploadInProgressFiles,
283+
extensionChangedFiles);
279284
}
280285

281286
// Throw exception if any files failed scan or upload in progress
@@ -319,7 +324,8 @@ public void processAttachment(
319324
Map<String, String> secondaryPropertiesWithInvalidDefinitions,
320325
List<String> noSDMRoles,
321326
List<String> scanFailedFiles,
322-
List<String> uploadInProgressFiles)
327+
List<String> uploadInProgressFiles,
328+
List<String> extensionChangedFiles)
323329
throws IOException {
324330
String id = (String) attachment.get("ID");
325331
String filenameInRequest = (String) attachment.get("fileName");
@@ -354,6 +360,7 @@ public void processAttachment(
354360
dbQuery.getPropertiesForID(
355361
attachmentEntity.get(), persistenceService, id, secondaryTypeProperties);
356362

363+
int extensionWarningsBefore = extensionChangedFiles.size();
357364
Map<String, String> updatedSecondaryProperties =
358365
prepareUpdatedProperties(
359366
attachmentEntity,
@@ -363,7 +370,13 @@ public void processAttachment(
363370
details.fileNameInDB,
364371
details.descriptionInDB,
365372
secondaryTypeProperties,
366-
propertiesInDB);
373+
propertiesInDB,
374+
extensionChangedFiles);
375+
376+
// If extension change was detected, revert filename to original
377+
if (extensionChangedFiles.size() > extensionWarningsBefore) {
378+
attachment.put("fileName", details.fileNameInDB);
379+
}
367380

368381
if (updatedSecondaryProperties.isEmpty()) {
369382
logger.debug("No changes detected for attachment ID: {}, skipping SDM update", id);
@@ -459,7 +472,8 @@ private Map<String, String> prepareUpdatedProperties(
459472
String fileNameInDB,
460473
String descriptionInDB,
461474
Map<String, String> secondaryTypeProperties,
462-
Map<String, String> propertiesInDB) {
475+
Map<String, String> propertiesInDB,
476+
List<String> extensionChangedFiles) {
463477
Map<String, String> updatedSecondaryProperties =
464478
SDMUtils.getUpdatedSecondaryProperties(
465479
attachmentEntity,
@@ -469,7 +483,11 @@ private Map<String, String> prepareUpdatedProperties(
469483
propertiesInDB);
470484

471485
AttachmentsHandlerUtils.updateFilenameProperty(
472-
fileNameInDB, filenameInRequest, fileNameInDB, updatedSecondaryProperties);
486+
fileNameInDB,
487+
filenameInRequest,
488+
fileNameInDB,
489+
updatedSecondaryProperties,
490+
extensionChangedFiles);
473491

474492
AttachmentsHandlerUtils.updateDescriptionProperty(
475493
null, descriptionInRequest, descriptionInDB, updatedSecondaryProperties, true);
@@ -563,7 +581,14 @@ private void handleWarnings(
563581
Map<String, String> badRequest,
564582
Map<String, String> propertyTitles,
565583
List<String> noSDMRoles,
584+
List<String> extensionChangedFiles,
566585
String contextInfo) {
586+
if (!extensionChangedFiles.isEmpty()) {
587+
logger.warn("File extension change attempted for files: {}", extensionChangedFiles);
588+
for (String warningMessage : extensionChangedFiles) {
589+
context.getMessages().warn(warningMessage);
590+
}
591+
}
567592
if (!fileNameWithRestrictedCharacters.isEmpty()) {
568593
logger.warn(
569594
"Files with restricted characters in filename: {}", fileNameWithRestrictedCharacters);

sdm/src/main/java/com/sap/cds/sdm/handler/applicationservice/helper/AttachmentsHandlerUtils.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -664,14 +664,17 @@ public static JSONObject fetchAttachmentDataFromSDM(
664664
*
665665
* @param fileNameInDB the filename currently in the database
666666
* @param filenameInRequest the filename from the request
667+
* @param fileNameInSDM the filename in SDM
667668
* @param updatedSecondaryProperties the map to update
669+
* @param extensionChangedFiles list to collect filenames where extension change was attempted
668670
* @throws ServiceException if filename validation fails
669671
*/
670672
public static void updateFilenameProperty(
671673
String fileNameInDB,
672674
String filenameInRequest,
673675
String fileNameInSDM,
674-
Map<String, String> updatedSecondaryProperties)
676+
Map<String, String> updatedSecondaryProperties,
677+
List<String> extensionChangedFiles)
675678
throws ServiceException {
676679
logger.debug(
677680
"Updating filename property - DB: {}, Request: {}, SDM: {}",
@@ -681,6 +684,9 @@ public static void updateFilenameProperty(
681684
if (fileNameInDB == null) {
682685
if (filenameInRequest != null) {
683686
if (!filenameInRequest.equals(fileNameInSDM)) {
687+
if (isFileExtensionChanged(fileNameInSDM, filenameInRequest, extensionChangedFiles)) {
688+
return;
689+
}
684690
logger.debug(
685691
"Filename updated from SDM value: {} to request value: {}",
686692
fileNameInSDM,
@@ -696,6 +702,9 @@ public static void updateFilenameProperty(
696702
logger.warn("Filename validation failed: filename cannot be empty");
697703
throw new ServiceException("Filename cannot be empty");
698704
} else if (!fileNameInDB.equals(filenameInRequest)) {
705+
if (isFileExtensionChanged(fileNameInDB, filenameInRequest, extensionChangedFiles)) {
706+
return;
707+
}
699708
logger.debug(
700709
"Filename updated from DB value: {} to request value: {}",
701710
fileNameInDB,
@@ -705,6 +714,30 @@ public static void updateFilenameProperty(
705714
}
706715
}
707716

717+
/**
718+
* Checks if the file extension has changed. If so, adds a warning message to the list and returns
719+
* true, indicating the rename should be skipped and the filename reverted.
720+
*
721+
* @param originalFileName the original filename (from DB or SDM)
722+
* @param newFileName the new filename from the request
723+
* @param extensionChangedFiles list to collect warning messages
724+
* @return true if extension changed (rename should be skipped), false otherwise
725+
*/
726+
private static boolean isFileExtensionChanged(
727+
String originalFileName, String newFileName, List<String> extensionChangedFiles) {
728+
if (SDMUtils.hasFileExtensionChanged(originalFileName, newFileName)) {
729+
String originalExtension = SDMUtils.getFileExtension(originalFileName);
730+
logger.warn("File extension change attempted: {} -> {}", originalFileName, newFileName);
731+
extensionChangedFiles.add(
732+
String.format(
733+
SDMUtils.getErrorMessage("FILE_EXTENSION_CHANGE_NOT_ALLOWED"),
734+
newFileName,
735+
originalExtension));
736+
return true;
737+
}
738+
return false;
739+
}
740+
708741
public static void updateDescriptionProperty(
709742
String descriptionInDB,
710743
String descriptionInRequest,

sdm/src/main/java/com/sap/cds/sdm/utilities/SDMUtils.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,42 @@ public static boolean hasRestrictedCharactersInName(String cmisName) {
134134
return matcher.find();
135135
}
136136

137+
/**
138+
* Extracts the file extension from a filename (lowercase, including the dot).
139+
*
140+
* @param fileName the filename to extract the extension from
141+
* @return the file extension (e.g. ".pdf"), or empty string if no valid extension exists
142+
*/
143+
public static String getFileExtension(String fileName) {
144+
if (fileName == null || fileName.isEmpty()) {
145+
return "";
146+
}
147+
int lastDotIndex = fileName.lastIndexOf('.');
148+
if (lastDotIndex <= 0 || lastDotIndex == fileName.length() - 1) {
149+
return "";
150+
}
151+
return fileName.substring(lastDotIndex).toLowerCase();
152+
}
153+
154+
/**
155+
* Checks whether the file extension has changed between the original and new filename.
156+
*
157+
* @param originalFileName the original filename
158+
* @param newFileName the new filename
159+
* @return true if the extension has changed, false otherwise
160+
*/
161+
public static boolean hasFileExtensionChanged(String originalFileName, String newFileName) {
162+
if (originalFileName == null || newFileName == null) {
163+
return false;
164+
}
165+
String originalExtension = getFileExtension(originalFileName);
166+
String newExtension = getFileExtension(newFileName);
167+
if (originalExtension.isEmpty() || newExtension.isEmpty()) {
168+
return false;
169+
}
170+
return !originalExtension.equals(newExtension);
171+
}
172+
137173
public static void prepareSecondaryProperties(
138174
Map<String, String> requestBody,
139175
Map<String, String> secondaryProperties,

sdm/src/test/java/integration/com/sap/cds/sdm/IntegrationTest_Chapters_MultipleFacet.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ void testCreateChapterAttachmentsWithUnsupportedCharacter() throws IOException {
552552
return;
553553
}
554554

555-
String restrictedName = "a/\\bc.pdf"; // \b becomes BACKSPACE
555+
String restrictedName = "a/\\bc.txt"; // \b becomes BACKSPACE
556556
response =
557557
api.renameAttachment(
558558
appUrl, chapterEntityName, facet[i], chapterID, ID2[i], restrictedName);
@@ -575,15 +575,15 @@ void testCreateChapterAttachmentsWithUnsupportedCharacter() throws IOException {
575575

576576
// ---------------- EXPECTED MESSAGE (EXACT) ----------------
577577
String expectedMessage =
578-
"\"a/\\bc.pdf\" contains unsupported characters ('/' or '\\'). Rename and try again.\n\n"
578+
"\"a/\\bc.txt\" contains unsupported characters ('/' or '\\'). Rename and try again.\n\n"
579579
+ "Table: attachments\n"
580580
+ "Page: IntegrationTestEntity";
581581

582582
if (message.equals(expectedMessage)) {
583583

584584
for (int i = 0; i < facet.length; i++) {
585585
api.renameAttachment(
586-
appUrl, chapterEntityName, facet[i], chapterID, ID2[i], "sample123.pdf");
586+
appUrl, chapterEntityName, facet[i], chapterID, ID2[i], "sample123.txt");
587587
}
588588

589589
response = api.saveEntityDraft(appUrl, bookEntityName, srvpath, bookID);
@@ -610,11 +610,11 @@ void testRenameSingleDuplicateInChapter() throws IOException {
610610

611611
if ("Entity in draft mode".equals(response)) {
612612
// To create a duplicate within the same facet, we need to rename ID2[i] to
613-
// the same name as an existing file in that facet. The existing files are:
614-
// sample.pdf (ID[0]), sample.txt (ID[1]), sample.exe (ID[2]) - these are the first uploads
615-
// We rename ID2[i] (sample123.pdf from test 8) to "sample.pdf" which already exists
616-
String[] duplicateNames = {"sample.pdf", "sample.txt", "sample.exe"};
617-
String[] validNames = {"unique_sample1.pdf", "unique_sample2.txt", "unique_sample3.exe"};
613+
// the same name as an existing file in that facet. After test 7, the existing files are:
614+
// sample123 (ID[0]), reference123 (ID[1]), footnote123 (ID[2])
615+
// We rename ID2[i] (sample123.txt from test 8) to these names which already exist
616+
String[] duplicateNames = {"sample123", "reference123", "footnote123"};
617+
String[] validNames = {"unique_sample1.txt", "unique_sample2.txt", "unique_sample3.txt"};
618618

619619
// Try to rename to duplicate file names (names that already exist in each facet)
620620
for (int i = 0; i < facet.length; i++) {

sdm/src/test/java/unit/com/sap/cds/sdm/handler/applicationservice/SDMUpdateAttachmentsHandlerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ public void testRenameWithNoSDMRoles() throws IOException {
406406
.when(
407407
() ->
408408
AttachmentsHandlerUtils.updateFilenameProperty(
409-
anyString(), anyString(), anyString(), any(Map.class)))
409+
anyString(), anyString(), anyString(), any(Map.class), any(List.class)))
410410
.thenAnswer(invocation -> null);
411411

412412
attachmentsMockStatic

sdm/src/test/java/unit/com/sap/cds/sdm/utilities/SDMUtilsTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,16 @@ public void testIsRestrictedCharactersInName() {
150150
assertFalse(SDMUtils.hasRestrictedCharactersInName(null));
151151
}
152152

153+
@Test
154+
public void testHasFileExtensionChanged() {
155+
assertTrue(SDMUtils.hasFileExtensionChanged("sample.pdf", "sample.dmg"));
156+
assertFalse(SDMUtils.hasFileExtensionChanged("sample.pdf", "renamed.pdf"));
157+
assertFalse(SDMUtils.hasFileExtensionChanged(null, "file.txt"));
158+
assertFalse(SDMUtils.hasFileExtensionChanged("file.txt", null));
159+
assertFalse(SDMUtils.hasFileExtensionChanged("sample.pdf", "sample123"));
160+
assertFalse(SDMUtils.hasFileExtensionChanged("sample", "sample123"));
161+
}
162+
153163
@Test
154164
public void prepareSecondaryPropertiesTest_withFilenameKey() {
155165
Map<String, String> requestBody = new HashMap<>();

0 commit comments

Comments
 (0)