From b3910a7dfcabb403b5ab4a8f1fdda0dda51faaaa Mon Sep 17 00:00:00 2001 From: Franck LECUYER Date: Mon, 4 Aug 2025 15:12:43 +0200 Subject: [PATCH 1/3] Ensure column id and column name unicity when duplicating a column Signed-off-by: Franck LECUYER --- .../service/SpreadsheetConfigService.java | 36 +++++++++++++++++-- .../SpreadsheetConfigIntegrationTest.java | 13 ++++++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java b/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java index 31d3863..016ba56 100644 --- a/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java +++ b/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java @@ -8,6 +8,7 @@ import jakarta.persistence.EntityNotFoundException; import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.tuple.Pair; import org.gridsuite.studyconfig.server.dto.*; import org.gridsuite.studyconfig.server.entities.ColumnEntity; import org.gridsuite.studyconfig.server.entities.GlobalFilterEntity; @@ -371,6 +372,35 @@ private static void reorderColumns(List columnOrder, List co columns.sort(Comparator.comparingInt(column -> columnOrder.indexOf(column.getUuid()))); } + private String newCandidate(String base, int n) { + return base + '(' + n + ')'; + } + + private Pair getDuplicateIdAndNameCandidate(SpreadsheetConfigEntity entity, String columnId, String columnName) { + String newColumnId = columnId; + String newColumnName = columnName; + + var existingColumnIds = entity.getColumns().stream().map(ColumnEntity::getId).collect(Collectors.toSet()); + var existingColumnNames = entity.getColumns().stream().map(ColumnEntity::getName).collect(Collectors.toSet()); + + if (existingColumnIds.contains(columnId)) { + int i = 1; + while (existingColumnIds.contains(newCandidate(columnId, i))) { + ++i; + } + newColumnId = newCandidate(columnId, i); + } + if (existingColumnNames.contains(columnName)) { + int i = 1; + while (existingColumnNames.contains(newCandidate(columnName, i))) { + ++i; + } + newColumnName = newCandidate(columnName, i); + } + + return Pair.of(newColumnId, newColumnName); + } + @Transactional public void duplicateColumn(UUID id, UUID columnId) { SpreadsheetConfigEntity entity = findEntityById(id); @@ -378,9 +408,9 @@ public void duplicateColumn(UUID id, UUID columnId) { .findFirst().orElseThrow(() -> new EntityNotFoundException(COLUMN_NOT_FOUND + columnId)); ColumnEntity columnCopy = columnEntity.toBuilder().build(); columnCopy.setUuid(UUID.randomUUID()); - columnCopy.setId(columnCopy.getId() + "copy"); - columnCopy.setName(columnCopy.getName() + "-copy"); - + Pair idAndName = getDuplicateIdAndNameCandidate(entity, columnCopy.getId(), columnCopy.getName()); + columnCopy.setId(idAndName.getLeft()); + columnCopy.setName(idAndName.getRight()); List columns = entity.getColumns(); columns.add(columns.indexOf(columnEntity) + 1, columnCopy); entity.setColumns(columns); diff --git a/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java b/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java index b41b8d4..e91c634 100644 --- a/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java +++ b/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java @@ -30,6 +30,7 @@ import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -328,12 +329,22 @@ void testDuplicateColumn() throws Exception { ColumnInfos duplicatedColumnInfos = configAfterDuplicate.columns().get(1); assertThat(columnInfos.uuid()).isNotEqualTo(duplicatedColumnInfos.uuid()); - assertThat(columnInfos.id()).isNotEqualTo(duplicatedColumnInfos.id()); + assertEquals(columnInfos.id() + "(1)", duplicatedColumnInfos.id()); + assertEquals(columnInfos.name() + "(1)", duplicatedColumnInfos.name()); assertThat(columnInfos.visible()).isEqualTo(duplicatedColumnInfos.visible()); assertThat(columnInfos.formula()).isEqualTo(duplicatedColumnInfos.formula()); assertThat(columnInfos.dependencies()).isEqualTo(duplicatedColumnInfos.dependencies()); assertThat(columnInfos.precision()).isEqualTo(duplicatedColumnInfos.precision()); + mockMvc.perform(post(URI_SPREADSHEET_CONFIG_GET_PUT + configId + URI_COLUMN_BASE + "/" + columnId + "/duplicate")) + .andExpect(status().isNoContent()); + configAfterDuplicate = getSpreadsheetConfig(configId); + assertThat(configAfterDuplicate.columns()).hasSize(6); + duplicatedColumnInfos = configAfterDuplicate.columns().get(1); + assertThat(columnInfos.uuid()).isNotEqualTo(duplicatedColumnInfos.uuid()); + assertEquals(columnInfos.id() + "(2)", duplicatedColumnInfos.id()); + assertEquals(columnInfos.name() + "(2)", duplicatedColumnInfos.name()); + mockMvc.perform(post(URI_SPREADSHEET_CONFIG_GET_PUT + configId + URI_COLUMN_BASE + "/" + UUID.randomUUID() + "/duplicate")) .andExpect(status().isNotFound()); } From b0d7d53526ab01ac8f9ad5050a6d8918832aef29 Mon Sep 17 00:00:00 2001 From: Franck LECUYER Date: Thu, 7 Aug 2025 17:47:03 +0200 Subject: [PATCH 2/3] Fix duplicated column renaming, to avoid unaccepted characters Signed-off-by: Franck LECUYER --- .../service/SpreadsheetConfigService.java | 40 ++++++++++--------- .../SpreadsheetConfigIntegrationTest.java | 8 ++-- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java b/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java index 016ba56..e4121d6 100644 --- a/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java +++ b/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java @@ -373,30 +373,34 @@ private static void reorderColumns(List columnOrder, List co } private String newCandidate(String base, int n) { - return base + '(' + n + ')'; + return base + '_' + n; + } + + /** + * Generates a unique value by appending a numeric suffix if the original value already exists. + * + * @param originalValue the original value to make unique + * @param existingValues set of existing values to avoid conflicts with + * @return a unique value, either the original or with a numeric suffix + */ + private String getUniqueValue(String originalValue, Set existingValues) { + if (!existingValues.contains(originalValue)) { + return originalValue; + } + + int i = 1; + while (existingValues.contains(newCandidate(originalValue, i))) { + ++i; + } + return newCandidate(originalValue, i); } private Pair getDuplicateIdAndNameCandidate(SpreadsheetConfigEntity entity, String columnId, String columnName) { - String newColumnId = columnId; - String newColumnName = columnName; - var existingColumnIds = entity.getColumns().stream().map(ColumnEntity::getId).collect(Collectors.toSet()); var existingColumnNames = entity.getColumns().stream().map(ColumnEntity::getName).collect(Collectors.toSet()); + String newColumnId = getUniqueValue(columnId, existingColumnIds); + String newColumnName = getUniqueValue(columnName, existingColumnNames); - if (existingColumnIds.contains(columnId)) { - int i = 1; - while (existingColumnIds.contains(newCandidate(columnId, i))) { - ++i; - } - newColumnId = newCandidate(columnId, i); - } - if (existingColumnNames.contains(columnName)) { - int i = 1; - while (existingColumnNames.contains(newCandidate(columnName, i))) { - ++i; - } - newColumnName = newCandidate(columnName, i); - } return Pair.of(newColumnId, newColumnName); } diff --git a/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java b/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java index e91c634..7d0019b 100644 --- a/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java +++ b/src/test/java/org/gridsuite/studyconfig/server/SpreadsheetConfigIntegrationTest.java @@ -329,8 +329,8 @@ void testDuplicateColumn() throws Exception { ColumnInfos duplicatedColumnInfos = configAfterDuplicate.columns().get(1); assertThat(columnInfos.uuid()).isNotEqualTo(duplicatedColumnInfos.uuid()); - assertEquals(columnInfos.id() + "(1)", duplicatedColumnInfos.id()); - assertEquals(columnInfos.name() + "(1)", duplicatedColumnInfos.name()); + assertEquals(columnInfos.id() + "_1", duplicatedColumnInfos.id()); + assertEquals(columnInfos.name() + "_1", duplicatedColumnInfos.name()); assertThat(columnInfos.visible()).isEqualTo(duplicatedColumnInfos.visible()); assertThat(columnInfos.formula()).isEqualTo(duplicatedColumnInfos.formula()); assertThat(columnInfos.dependencies()).isEqualTo(duplicatedColumnInfos.dependencies()); @@ -342,8 +342,8 @@ void testDuplicateColumn() throws Exception { assertThat(configAfterDuplicate.columns()).hasSize(6); duplicatedColumnInfos = configAfterDuplicate.columns().get(1); assertThat(columnInfos.uuid()).isNotEqualTo(duplicatedColumnInfos.uuid()); - assertEquals(columnInfos.id() + "(2)", duplicatedColumnInfos.id()); - assertEquals(columnInfos.name() + "(2)", duplicatedColumnInfos.name()); + assertEquals(columnInfos.id() + "_2", duplicatedColumnInfos.id()); + assertEquals(columnInfos.name() + "_2", duplicatedColumnInfos.name()); mockMvc.perform(post(URI_SPREADSHEET_CONFIG_GET_PUT + configId + URI_COLUMN_BASE + "/" + UUID.randomUUID() + "/duplicate")) .andExpect(status().isNotFound()); From da4284edf351314ee428e53c965a64f800016ac5 Mon Sep 17 00:00:00 2001 From: Franck LECUYER Date: Thu, 7 Aug 2025 17:51:21 +0200 Subject: [PATCH 3/3] Fix checkstyle pb Signed-off-by: Franck LECUYER --- .../studyconfig/server/service/SpreadsheetConfigService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java b/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java index e4121d6..c5bd1ce 100644 --- a/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java +++ b/src/main/java/org/gridsuite/studyconfig/server/service/SpreadsheetConfigService.java @@ -401,7 +401,6 @@ private Pair getDuplicateIdAndNameCandidate(SpreadsheetConfigEnt String newColumnId = getUniqueValue(columnId, existingColumnIds); String newColumnName = getUniqueValue(columnName, existingColumnNames); - return Pair.of(newColumnId, newColumnName); }