From bc75a9c1e2207b891e69870b7ab95c337344728b Mon Sep 17 00:00:00 2001
From: Sonia Zorba <sonia.zorba@inaf.it>
Date: Wed, 14 Jul 2021 18:21:30 +0200
Subject: [PATCH] Added non-standard parameter on job list endpoint to filter
 on transfer view type (useful for retrieving the list of generated tar/zip
 archives from UI)

---
 .../inaf/oats/vospace/TransferController.java | 19 +++-----
 .../inaf/oats/vospace/persistence/JobDAO.java | 14 ++++++
 .../oats/vospace/TransferControllerTest.java  | 45 +++++++++++++++++--
 .../oats/vospace/persistence/JobDAOTest.java  | 19 +++++---
 src/test/resources/test-data.sql              |  2 +-
 5 files changed, 74 insertions(+), 25 deletions(-)

diff --git a/src/main/java/it/inaf/oats/vospace/TransferController.java b/src/main/java/it/inaf/oats/vospace/TransferController.java
index 235003c..c7c2d51 100644
--- a/src/main/java/it/inaf/oats/vospace/TransferController.java
+++ b/src/main/java/it/inaf/oats/vospace/TransferController.java
@@ -173,6 +173,7 @@ public class TransferController {
             @RequestParam(value = "PHASE", required = false) Optional<List<ExecutionPhase>> phase,
             @RequestParam(value = "AFTER", required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Optional<LocalDateTime> after,
             @RequestParam(value = "LAST", required = false) Optional<Integer> last,
+            @RequestParam(value = "VIEW", required = false) Optional<List<String>> views,
             @RequestParam(value = "direction", required = false) Optional<List<JobService.JobDirection>> direction,
             User principal) {
 
@@ -184,21 +185,11 @@ public class TransferController {
 
         String userId = principal.getName();
 
-        List<ExecutionPhase> phaseList;
-        if (phase.isPresent()) {
-            phaseList = phase.get();
-        } else {
-            phaseList = List.of();
-        }
-
-        List<JobService.JobDirection> directionList;
-        if (direction.isPresent()) {
-            directionList = direction.get();
-        } else {
-            directionList = List.of();
-        }
+        List<ExecutionPhase> phaseList = phase.orElse(List.of());
+        List<JobService.JobDirection> directionList = direction.orElse(List.of());
+        List<String> viewsList = views.orElse(List.of());
 
-        Jobs jobs = jobDAO.getJobs(userId, phaseList, directionList, after, last);
+        Jobs jobs = jobDAO.getJobs(userId, phaseList, directionList, viewsList, after, last);
 
         return ResponseEntity.ok(jobs);
     }
diff --git a/src/main/java/it/inaf/oats/vospace/persistence/JobDAO.java b/src/main/java/it/inaf/oats/vospace/persistence/JobDAO.java
index fef4d39..e2b5236 100644
--- a/src/main/java/it/inaf/oats/vospace/persistence/JobDAO.java
+++ b/src/main/java/it/inaf/oats/vospace/persistence/JobDAO.java
@@ -31,6 +31,7 @@ import org.springframework.stereotype.Repository;
 import java.util.ArrayList;
 import java.time.LocalDateTime;
 import java.math.BigDecimal;
+import java.util.Collections;
 import net.ivoa.xml.uws.v1.ErrorType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -149,6 +150,7 @@ public class JobDAO {
     public Jobs getJobs(String userId,
             List<ExecutionPhase> phaseList,
             List<JobService.JobDirection> directionList,
+            List<String> viewList,
             Optional<LocalDateTime> after,
             Optional<Integer> last
     ) {
@@ -198,6 +200,18 @@ public class JobDAO {
             }
             sb.append(")");
         }
+        
+        // Fill conditions on views list
+        if (!viewList.isEmpty()) {
+            sb.append(" AND (")
+                    .append(String.join(" OR ",
+                            Collections.nCopies(viewList.size(), "job_info->'transfer'->'view'->>'uri' = ?")))
+                    .append(")");
+            for (String view : viewList) {
+                queryParams.add(view);
+                queryParamTypes.add(Types.VARCHAR);
+            }
+        }
 
         // Fill conditions on creation date
         if (after.isPresent()) {
diff --git a/src/test/java/it/inaf/oats/vospace/TransferControllerTest.java b/src/test/java/it/inaf/oats/vospace/TransferControllerTest.java
index eff8255..d85292b 100644
--- a/src/test/java/it/inaf/oats/vospace/TransferControllerTest.java
+++ b/src/test/java/it/inaf/oats/vospace/TransferControllerTest.java
@@ -8,6 +8,7 @@ package it.inaf.oats.vospace;
 import it.inaf.ia2.aa.data.User;
 import static it.inaf.oats.vospace.VOSpaceXmlTestUtil.loadDocument;
 import it.inaf.oats.vospace.datamodel.NodeProperties;
+import it.inaf.oats.vospace.datamodel.Views;
 import it.inaf.oats.vospace.exception.ErrorSummaryFactory;
 import it.inaf.oats.vospace.exception.PermissionDeniedException;
 import it.inaf.oats.vospace.persistence.JobDAO;
@@ -357,7 +358,7 @@ public class TransferControllerTest {
     @Test
     public void testGetJobs() throws Exception {
 
-        when(jobDao.getJobs(eq("user1"), any(), any(), any(), any()))
+        when(jobDao.getJobs(eq("user1"), any(), any(), any(), any(), any()))
                 .thenReturn(this.getFakeJobs());
 
         mockMvc.perform(get("/transfers")
@@ -367,12 +368,48 @@ public class TransferControllerTest {
                 .andDo(print())
                 .andExpect(status().is4xxClientError());
 
-        String xml2 = mockMvc.perform(get("/transfers")
+        mockMvc.perform(get("/transfers")
                 .header("Authorization", "Bearer user1_token")
                 .accept(MediaType.APPLICATION_XML))
                 .andDo(print())
-                .andExpect(status().isOk())
-                .andReturn().getResponse().getContentAsString();
+                .andExpect(status().isOk());
+
+        // direction query parameter
+        mockMvc.perform(get("/transfers")
+                .param("direction", "pullFromVoSpace")
+                .header("Authorization", "Bearer user1_token")
+                .accept(MediaType.APPLICATION_XML))
+                .andDo(print())
+                .andExpect(status().isOk());
+
+        verify(jobDao, times(1)).getJobs(eq("user1"), any(), argThat(v -> {
+            return v.size() == 1 && v.contains(JobService.JobDirection.pullFromVoSpace);
+        }), any(), any(), any());
+
+        // PHASE query parameter
+        mockMvc.perform(get("/transfers")
+                .param("PHASE", ExecutionPhase.EXECUTING.value())
+                .header("Authorization", "Bearer user1_token")
+                .accept(MediaType.APPLICATION_XML))
+                .andDo(print())
+                .andExpect(status().isOk());
+
+        verify(jobDao, times(1)).getJobs(eq("user1"), argThat(v -> {
+            return v.size() == 1 && v.contains(ExecutionPhase.EXECUTING);
+        }), any(), any(), any(), any());
+
+        // VIEW query parameters
+        mockMvc.perform(get("/transfers")
+                .param("VIEW", Views.TAR_VIEW_URI)
+                .param("VIEW", Views.ZIP_VIEW_URI)
+                .header("Authorization", "Bearer user1_token")
+                .accept(MediaType.APPLICATION_XML))
+                .andDo(print())
+                .andExpect(status().isOk());
+
+        verify(jobDao, times(1)).getJobs(eq("user1"), any(), any(), argThat(v -> {
+            return v.size() == 2 && v.contains(Views.TAR_VIEW_URI) && v.contains(Views.ZIP_VIEW_URI);
+        }), any(), any());
     }
 
     @Test
diff --git a/src/test/java/it/inaf/oats/vospace/persistence/JobDAOTest.java b/src/test/java/it/inaf/oats/vospace/persistence/JobDAOTest.java
index 1657cee..922a6d7 100644
--- a/src/test/java/it/inaf/oats/vospace/persistence/JobDAOTest.java
+++ b/src/test/java/it/inaf/oats/vospace/persistence/JobDAOTest.java
@@ -6,6 +6,7 @@
 package it.inaf.oats.vospace.persistence;
 
 import it.inaf.oats.vospace.JobService;
+import it.inaf.oats.vospace.datamodel.Views;
 import java.util.List;
 import javax.sql.DataSource;
 import net.ivoa.xml.uws.v1.ExecutionPhase;
@@ -202,10 +203,11 @@ public class JobDAOTest {
         String user = "user1";
         List<ExecutionPhase> phaseList = List.of();
         List<JobService.JobDirection> directionList = List.of();
+        List<String> viewList = List.of();
         Optional<LocalDateTime> after = Optional.ofNullable(null);
         Optional<Integer> last = Optional.ofNullable(null);
 
-        Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
+        Jobs jobs = dao.getJobs(user, phaseList, directionList, viewList, after, last);
 
         assertTrue(jobs != null);
         List<ShortJobDescription> sjdList = jobs.getJobref();
@@ -227,10 +229,11 @@ public class JobDAOTest {
         String user = "user1";
         List<ExecutionPhase> phaseList = List.of();
         List<JobService.JobDirection> directionList = List.of();
+        List<String> viewList = List.of();
         Optional<LocalDateTime> after = Optional.ofNullable(null);
         Optional<Integer> last = Optional.of(2);
 
-        Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
+        Jobs jobs = dao.getJobs(user, phaseList, directionList, viewList, after, last);
         List<ShortJobDescription> sjdList = jobs.getJobref();
         assertEquals(2, sjdList.size());
 
@@ -243,10 +246,11 @@ public class JobDAOTest {
         List<ExecutionPhase> phaseList
                 = List.of(ExecutionPhase.PENDING, ExecutionPhase.EXECUTING);
         List<JobService.JobDirection> directionList = List.of();
+        List<String> viewList = List.of();
         Optional<LocalDateTime> after = Optional.ofNullable(null);
         Optional<Integer> last = Optional.ofNullable(null);
 
-        Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
+        Jobs jobs = dao.getJobs(user, phaseList, directionList, viewList, after, last);
         List<ShortJobDescription> sjdList = jobs.getJobref();
         assertEquals(sjdList.size(), 2);
         assertEquals("pippo5", sjdList.get(0).getId());
@@ -261,10 +265,11 @@ public class JobDAOTest {
         List<JobService.JobDirection> directionList
                 = List.of(JobService.JobDirection.pullFromVoSpace,
                         JobService.JobDirection.pullToVoSpace);
+        List<String> viewList = List.of();
 
         Optional<LocalDateTime> after = Optional.ofNullable(null);
         Optional<Integer> last = Optional.ofNullable(null);
-        Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
+        Jobs jobs = dao.getJobs(user, phaseList, directionList, viewList, after, last);
         List<ShortJobDescription> sjdList = jobs.getJobref();
         assertEquals(2, sjdList.size());
         assertEquals("pippo3", sjdList.get(0).getId());
@@ -277,13 +282,14 @@ public class JobDAOTest {
         String user = "user1";
         List<ExecutionPhase> phaseList = List.of();
         List<JobService.JobDirection> directionList = List.of();
+        List<String> viewList = List.of();
 
         LocalDateTime ldt
                 = LocalDateTime.of(2013, Month.FEBRUARY, 7, 18, 15);
         Optional<LocalDateTime> after = Optional.of(ldt);
 
         Optional<Integer> last = Optional.ofNullable(null);
-        Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
+        Jobs jobs = dao.getJobs(user, phaseList, directionList, viewList, after, last);
         List<ShortJobDescription> sjdList = jobs.getJobref();
         assertEquals(2, sjdList.size());
         assertEquals("pippo5", sjdList.get(0).getId());
@@ -299,13 +305,14 @@ public class JobDAOTest {
         List<JobService.JobDirection> directionList
                 = List.of(JobService.JobDirection.pullFromVoSpace,
                         JobService.JobDirection.pullToVoSpace);
+        List<String> viewList = List.of(Views.TAR_VIEW_URI, Views.ZIP_VIEW_URI);
 
         LocalDateTime ldt
                 = LocalDateTime.of(2013, Month.FEBRUARY, 7, 18, 15);
         Optional<LocalDateTime> after = Optional.of(ldt);
 
         Optional<Integer> last = Optional.of(2);
-        Jobs jobs = dao.getJobs(user, phaseList, directionList, after, last);
+        Jobs jobs = dao.getJobs(user, phaseList, directionList, viewList, after, last);
         List<ShortJobDescription> sjdList = jobs.getJobref();
         assertEquals(1, sjdList.size());
         assertEquals("pippo3", sjdList.get(0).getId());
diff --git a/src/test/resources/test-data.sql b/src/test/resources/test-data.sql
index 4d3234f..53f9735 100644
--- a/src/test/resources/test-data.sql
+++ b/src/test/resources/test-data.sql
@@ -40,7 +40,7 @@ DELETE FROM job;
 
 INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo1', 'user1', 'pullFromVoSpace', 'ARCHIVED', NULL, NULL, '2011-06-22 19:10:25', NULL, NULL);
 INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo2', 'user1', 'pullToVoSpace', 'PENDING', NULL, NULL, '2012-06-22 19:10:25', NULL, NULL);
-INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo3', 'user1', 'pullFromVoSpace', 'QUEUED', NULL, NULL, '2013-06-22 19:10:25', NULL, NULL);
+INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo3', 'user1', 'pullFromVoSpace', 'QUEUED', NULL, NULL, '2013-06-22 19:10:25', '{"transfer": {"view": {"uri": "ivo://ia2.inaf.it/vospace/views#zip"}}}', NULL);
 INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo4', 'user2', 'copyNode', 'PENDING', NULL, NULL, '2014-06-22 19:10:25', NULL, NULL);
 INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo5', 'user1', 'pushToVoSpace', 'EXECUTING', NULL, NULL, '2015-06-22 19:10:25', NULL, NULL);
 INSERT INTO job (job_id, owner_id, job_type, phase, start_time, end_time, creation_time, job_info, results) VALUES ('pippo6', 'user2', 'pullFromVoSpace', 'PENDING', NULL, NULL, '2015-06-22 19:10:25', NULL, NULL);
-- 
GitLab