From f26a0e38ce8a2c977845deb4729f917755b7c345 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <p.gawron@atcomp.pl>
Date: Wed, 9 Apr 2025 10:13:23 +0200
Subject: [PATCH] fix problem with uploading data overlay

---
 .../mapviewer/services/impl/FileService.java  | 22 +++++++-----
 .../services/interfaces/IFileService.java     |  5 +--
 .../project/overlay/NewDataOverlayDTO.java    | 10 ++++++
 .../project/overlay/NewOverlayController.java | 29 ++++++++++++++--
 .../overlay/NewOverlayControllerTest.java     | 34 +++++++++++++++++++
 5 files changed, 86 insertions(+), 14 deletions(-)

diff --git a/service/src/main/java/lcsb/mapviewer/services/impl/FileService.java b/service/src/main/java/lcsb/mapviewer/services/impl/FileService.java
index c92d07d336..9344c78568 100644
--- a/service/src/main/java/lcsb/mapviewer/services/impl/FileService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/impl/FileService.java
@@ -1,25 +1,24 @@
 package lcsb.mapviewer.services.impl;
 
-import java.io.FileNotFoundException;
-
-import org.hibernate.Hibernate;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
 import lcsb.mapviewer.annotation.cache.BigFileCache;
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
 import lcsb.mapviewer.model.user.User;
 import lcsb.mapviewer.persist.dao.cache.UploadedFileEntryDao;
 import lcsb.mapviewer.services.interfaces.IFileService;
+import org.hibernate.Hibernate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.FileNotFoundException;
 
 @Transactional
 @Service
 public class FileService implements IFileService {
 
-  private UploadedFileEntryDao uploadedFileEntryDao;
+  private final UploadedFileEntryDao uploadedFileEntryDao;
 
-  private BigFileCache bigFileCache;
+  private final BigFileCache bigFileCache;
 
   @Autowired
   public FileService(final UploadedFileEntryDao uploadedFileEntryDao, final BigFileCache bigFileCache) {
@@ -66,4 +65,9 @@ public class FileService implements IFileService {
     uploadedFileEntryDao.delete(fileEntry);
   }
 
+  @Override
+  public byte[] getContentById(final Integer fileId) {
+    return getById(fileId).getFileContent();
+  }
+
 }
diff --git a/service/src/main/java/lcsb/mapviewer/services/interfaces/IFileService.java b/service/src/main/java/lcsb/mapviewer/services/interfaces/IFileService.java
index 505469a71e..c5638e49c9 100644
--- a/service/src/main/java/lcsb/mapviewer/services/interfaces/IFileService.java
+++ b/service/src/main/java/lcsb/mapviewer/services/interfaces/IFileService.java
@@ -1,10 +1,10 @@
 package lcsb.mapviewer.services.interfaces;
 
-import java.io.FileNotFoundException;
-
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
 import lcsb.mapviewer.model.user.User;
 
+import java.io.FileNotFoundException;
+
 public interface IFileService {
 
   UploadedFileEntry getById(final Integer id);
@@ -19,4 +19,5 @@ public interface IFileService {
 
   void delete(UploadedFileEntry fileEntry);
 
+  byte[] getContentById(Integer fileId);
 }
diff --git a/web/src/main/java/lcsb/mapviewer/web/api/project/overlay/NewDataOverlayDTO.java b/web/src/main/java/lcsb/mapviewer/web/api/project/overlay/NewDataOverlayDTO.java
index 93b51ca8b2..cbfe920314 100644
--- a/web/src/main/java/lcsb/mapviewer/web/api/project/overlay/NewDataOverlayDTO.java
+++ b/web/src/main/java/lcsb/mapviewer/web/api/project/overlay/NewDataOverlayDTO.java
@@ -30,6 +30,8 @@ public class NewDataOverlayDTO extends AbstractDTO {
   @Min(0)
   private Integer orderIndex;
 
+  private Integer fileId;
+
   @NotNull
   private String description;
 
@@ -112,4 +114,12 @@ public class NewDataOverlayDTO extends AbstractDTO {
   public void setGroup(final Integer group) {
     this.group = group;
   }
+
+  public Integer getFileId() {
+    return fileId;
+  }
+
+  public void setFileId(final Integer fileId) {
+    this.fileId = fileId;
+  }
 }
diff --git a/web/src/main/java/lcsb/mapviewer/web/api/project/overlay/NewOverlayController.java b/web/src/main/java/lcsb/mapviewer/web/api/project/overlay/NewOverlayController.java
index af9b4188ba..ae5be3ee31 100644
--- a/web/src/main/java/lcsb/mapviewer/web/api/project/overlay/NewOverlayController.java
+++ b/web/src/main/java/lcsb/mapviewer/web/api/project/overlay/NewOverlayController.java
@@ -3,6 +3,9 @@ package lcsb.mapviewer.web.api.project.overlay;
 import lcsb.mapviewer.api.BaseController;
 import lcsb.mapviewer.api.QueryException;
 import lcsb.mapviewer.common.Pair;
+import lcsb.mapviewer.common.TextFileUtils;
+import lcsb.mapviewer.converter.ColorSchemaReader;
+import lcsb.mapviewer.converter.zip.ZipEntryFileFactory;
 import lcsb.mapviewer.model.Project;
 import lcsb.mapviewer.model.cache.UploadedFileEntry;
 import lcsb.mapviewer.model.map.BioEntity;
@@ -10,6 +13,7 @@ import lcsb.mapviewer.model.map.model.ModelData;
 import lcsb.mapviewer.model.overlay.DataOverlay;
 import lcsb.mapviewer.model.overlay.DataOverlayEntry;
 import lcsb.mapviewer.model.overlay.DataOverlayGroup;
+import lcsb.mapviewer.model.overlay.InvalidDataOverlayException;
 import lcsb.mapviewer.model.security.PrivilegeType;
 import lcsb.mapviewer.model.user.User;
 import lcsb.mapviewer.persist.dao.map.DataOverlayGroupProperty;
@@ -45,8 +49,10 @@ import org.springframework.web.bind.annotation.RestController;
 
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -134,7 +140,7 @@ public class NewOverlayController extends BaseController {
       final @Valid @NotBlank @PathVariable(value = "projectId") String projectId,
       final @Valid @RequestBody NewDataOverlayDTO data,
       final Authentication authentication)
-      throws QueryException, ObjectNotFoundException {
+      throws QueryException, ObjectNotFoundException, IOException, InvalidDataOverlayException {
 
     final User user = userService.getUserByLogin(authentication.getName());
     final Project project = projectService.getProjectByProjectId(projectId);
@@ -142,12 +148,29 @@ public class NewOverlayController extends BaseController {
       throw new ObjectNotFoundException("Project with given projectId does not exist");
     }
 
-    final UploadedFileEntry entry = createEmptyFile(user);
-
     final DataOverlay overlay = new DataOverlay();
     data.saveToDataOverlay(overlay, getGroupIdToGroup(projectId, user.getLogin()));
     overlay.setProject(project);
     overlay.setCreator(user);
+
+    UploadedFileEntry entry;
+    if (data.getFileId() != null) {
+      entry = fileService.getById(data.getFileId());
+      byte[] content = fileService.getContentById(data.getFileId());
+
+      final ColorSchemaReader reader = new ColorSchemaReader();
+
+      final Map<String, String> parameters = TextFileUtils.getHeaderParametersFromFile(new ByteArrayInputStream(content));
+      final Collection<DataOverlayEntry> schemas = reader.readColorSchema(new ByteArrayInputStream(content), parameters);
+      overlay.addEntries(schemas);
+      String nonMatchingAlpha = parameters.get(ZipEntryFileFactory.NON_MATCHING_ALPHA);
+      if (nonMatchingAlpha != null) {
+        overlay.setNotMatchingAlpha(nonMatchingAlpha);
+      }
+    } else {
+      entry = createEmptyFile(user);
+    }
+
     overlay.setInputData(entry);
     dataOverlayService.add(overlay);
 
diff --git a/web/src/test/java/lcsb/mapviewer/web/api/project/overlay/NewOverlayControllerTest.java b/web/src/test/java/lcsb/mapviewer/web/api/project/overlay/NewOverlayControllerTest.java
index 0c8297e06c..b4aeab4eba 100644
--- a/web/src/test/java/lcsb/mapviewer/web/api/project/overlay/NewOverlayControllerTest.java
+++ b/web/src/test/java/lcsb/mapviewer/web/api/project/overlay/NewOverlayControllerTest.java
@@ -2,13 +2,16 @@ package lcsb.mapviewer.web.api.project.overlay;
 
 import com.fasterxml.jackson.core.type.TypeReference;
 import lcsb.mapviewer.common.Configuration;
+import lcsb.mapviewer.converter.zip.ZipEntryFileFactory;
 import lcsb.mapviewer.model.Project;
+import lcsb.mapviewer.model.cache.UploadedFileEntry;
 import lcsb.mapviewer.model.map.layout.ReferenceGenomeType;
 import lcsb.mapviewer.model.map.model.ModelData;
 import lcsb.mapviewer.model.map.model.ModelSubmodelConnection;
 import lcsb.mapviewer.model.map.reaction.Reaction;
 import lcsb.mapviewer.model.map.species.Element;
 import lcsb.mapviewer.model.overlay.DataOverlay;
+import lcsb.mapviewer.model.overlay.DataOverlayEntry;
 import lcsb.mapviewer.model.overlay.DataOverlayGroup;
 import lcsb.mapviewer.model.overlay.DataOverlayType;
 import lcsb.mapviewer.model.security.PrivilegeType;
@@ -32,8 +35,10 @@ import org.springframework.test.web.servlet.RequestBuilder;
 import javax.servlet.http.HttpServletResponse;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -530,4 +535,33 @@ public class NewOverlayControllerTest extends ControllerIntegrationTest {
     mockMvc.perform(request)
         .andExpect(status().isForbidden());
   }
+
+  @Test
+  public void testCreateOverlayWithFile() throws Exception {
+    String content = "#" + ZipEntryFileFactory.NON_MATCHING_ALPHA + "=125\n" + createOverlayContentForAllEntities(map);
+    UploadedFileEntry file = createFile(content, admin);
+    final MockHttpSession session = createSession(BUILT_IN_TEST_ADMIN_LOGIN, BUILT_IN_TEST_ADMIN_PASSWORD);
+
+    final NewDataOverlayDTO data = createDataOverlayDTO();
+    data.setFileId(file.getId());
+
+    final RequestBuilder request = post("/minerva/new_api/projects/{projectId}/overlays/", TEST_PROJECT)
+        .contentType(MediaType.APPLICATION_JSON)
+        .content(objectMapper.writeValueAsString(data))
+        .session(session);
+
+    final MockHttpServletResponse response = mockMvc.perform(request)
+        .andExpect(status().isCreated())
+        .andReturn().getResponse();
+    assertNotNull(response.getHeader("ETag"));
+    final Map<String, Object> result = objectMapper.readValue(response.getContentAsString(), new TypeReference<Map<String, Object>>() {
+    });
+
+    Set<DataOverlayEntry> entries = dataOverlayService.getDataOverlayEntriesById(TEST_PROJECT, (int) result.get("id"));
+
+    assertFalse(entries.isEmpty());
+
+    DataOverlay overlay = dataOverlayService.getDataOverlayById((int) result.get("id"));
+    assertEquals((Integer) 125, overlay.getNotMatchingAlpha());
+  }
 }
-- 
GitLab