From e906ee239fb30791c76a6e3d9410e75f24962f01 Mon Sep 17 00:00:00 2001
From: Sonia Zorba <sonia.zorba@inaf.it>
Date: Wed, 14 Jul 2021 14:57:50 +0200
Subject: [PATCH] Used view parameters instead of multiple targets for tar/zip
 archive generation

---
 .../inaf/oats/vospace/FileServiceClient.java  | 34 +++++++--
 .../oats/vospace/FileServiceClientTest.java   | 69 ++++++++++++++++++-
 .../it/inaf/oats/vospace/UriServiceTest.java  | 31 ++++++---
 3 files changed, 120 insertions(+), 14 deletions(-)

diff --git a/src/main/java/it/inaf/oats/vospace/FileServiceClient.java b/src/main/java/it/inaf/oats/vospace/FileServiceClient.java
index 55fe579..d7f085a 100644
--- a/src/main/java/it/inaf/oats/vospace/FileServiceClient.java
+++ b/src/main/java/it/inaf/oats/vospace/FileServiceClient.java
@@ -7,6 +7,8 @@ package it.inaf.oats.vospace;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import it.inaf.ia2.aa.data.User;
+import it.inaf.oats.vospace.datamodel.Views;
+import it.inaf.oats.vospace.exception.InvalidArgumentException;
 import java.io.OutputStream;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -39,8 +41,32 @@ public class FileServiceClient {
 
     public String startArchiveJob(Transfer transfer, String jobId) {
 
-        List<String> vosPaths = transfer.getTarget().stream()
-                .map(p -> p.substring("vos://".length() + authority.length())).collect(Collectors.toList());
+        if (transfer.getTarget().size() != 1) {
+            throw new IllegalArgumentException("Target size is " + transfer.getTarget().size());
+        }
+
+        String target = transfer.getTarget().get(0);
+
+        String viewUri = transfer.getView().getUri();
+
+        // Generate list of paths using view include parameters
+        List<String> vosPaths = transfer.getView().getParam().stream()
+                .map(p -> {
+                    if (p.getUri().equals(viewUri + "/include")) {
+                        if (p.getValue().contains("../")) {
+                            throw new InvalidArgumentException("Relative paths are not supported");
+                        }
+                        return target + "/" + p.getValue();
+                    } else {
+                        throw new InvalidArgumentException("Unsupported view parameter: " + p.getUri());
+                    }
+                })
+                .collect(Collectors.toList());
+
+        if (vosPaths.isEmpty()) {
+            // Add target path
+            vosPaths.add(target.substring("vos://".length() + authority.length()));
+        }
 
         ArchiveRequest archiveRequest = new ArchiveRequest();
         archiveRequest.setJobId(jobId);
@@ -98,9 +124,9 @@ public class FileServiceClient {
 
     private static String archiveTypeFromViewUri(String viewUri) {
         switch (viewUri) {
-            case "ivo://ia2.inaf.it/vospace/views#tar":
+            case Views.TAR_VIEW_URI:
                 return "TAR";
-            case "ivo://ia2.inaf.it/vospace/views#zip":
+            case Views.ZIP_VIEW_URI:
                 return "ZIP";
             default:
                 throw new IllegalArgumentException("Archive type not defined for " + viewUri);
diff --git a/src/test/java/it/inaf/oats/vospace/FileServiceClientTest.java b/src/test/java/it/inaf/oats/vospace/FileServiceClientTest.java
index aded67f..ae6af0a 100644
--- a/src/test/java/it/inaf/oats/vospace/FileServiceClientTest.java
+++ b/src/test/java/it/inaf/oats/vospace/FileServiceClientTest.java
@@ -7,13 +7,16 @@ package it.inaf.oats.vospace;
 
 import it.inaf.ia2.aa.data.User;
 import it.inaf.oats.vospace.datamodel.Views;
+import it.inaf.oats.vospace.exception.InvalidArgumentException;
 import java.io.ByteArrayOutputStream;
 import java.net.URI;
 import java.util.Arrays;
 import javax.servlet.http.HttpServletRequest;
+import net.ivoa.xml.vospace.v2.Param;
 import net.ivoa.xml.vospace.v2.Transfer;
 import net.ivoa.xml.vospace.v2.View;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.fail;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -75,15 +78,79 @@ public class FileServiceClientTest {
         }
     }
 
+    @Test
+    public void testArchiveNoInclude() {
+
+        Transfer transfer = new Transfer();
+        transfer.setDirection("pullFromVoSpace");
+        transfer.setTarget(Arrays.asList("vos://example.com!vospace/mydir"));
+        View view = new View();
+        view.setUri(Views.ZIP_VIEW_URI);
+        transfer.setView(view);
+
+        testStartArchiveJob(transfer);
+    }
+
+    @Test
+    public void testInvalidViewParam() {
+
+        Transfer transfer = new Transfer();
+        transfer.setDirection("pullFromVoSpace");
+        transfer.setTarget(Arrays.asList("vos://example.com!vospace/parent_dir"));
+        View view = new View();
+        view.setUri(Views.TAR_VIEW_URI);
+        transfer.setView(view);
+
+        Param param1 = new Param();
+        param1.setUri("invalid");
+        param1.setValue("file1");
+        view.getParam().add(param1);
+
+        assertThrows(InvalidArgumentException.class, () -> testStartArchiveJob(transfer));
+    }
+
+    @Test
+    public void testInvalidViewParamPath() {
+
+        Transfer transfer = new Transfer();
+        transfer.setDirection("pullFromVoSpace");
+        transfer.setTarget(Arrays.asList("vos://example.com!vospace/parent_dir"));
+        View view = new View();
+        view.setUri(Views.TAR_VIEW_URI);
+        transfer.setView(view);
+
+        Param param1 = new Param();
+        param1.setUri(Views.TAR_VIEW_URI + "/include");
+        param1.setValue("../file1");
+        view.getParam().add(param1);
+
+        assertThrows(InvalidArgumentException.class, () -> testStartArchiveJob(transfer));
+    }
+
     private void testStartArchiveJob(String viewUri) {
 
         Transfer transfer = new Transfer();
         transfer.setDirection("pullFromVoSpace");
-        transfer.setTarget(Arrays.asList("vos://example.com!vospace/file1", "vos://example.com!vospace/file2"));
+        transfer.setTarget(Arrays.asList("vos://example.com!vospace/parent_dir"));
         View view = new View();
         view.setUri(viewUri);
         transfer.setView(view);
 
+        Param param1 = new Param();
+        param1.setUri(viewUri + "/include");
+        param1.setValue("file1");
+        view.getParam().add(param1);
+
+        Param param2 = new Param();
+        param2.setUri(viewUri + "/include");
+        param2.setValue("file2");
+        view.getParam().add(param2);
+
+        testStartArchiveJob(transfer);
+    }
+
+    private void testStartArchiveJob(Transfer transfer) {
+
         User user = mock(User.class);
         when(user.getAccessToken()).thenReturn("<token>");
         when(request.getUserPrincipal()).thenReturn(user);
diff --git a/src/test/java/it/inaf/oats/vospace/UriServiceTest.java b/src/test/java/it/inaf/oats/vospace/UriServiceTest.java
index 8806661..4a59ad7 100644
--- a/src/test/java/it/inaf/oats/vospace/UriServiceTest.java
+++ b/src/test/java/it/inaf/oats/vospace/UriServiceTest.java
@@ -24,6 +24,7 @@ import net.ivoa.xml.uws.v1.JobSummary;
 import net.ivoa.xml.vospace.v2.ContainerNode;
 import net.ivoa.xml.vospace.v2.DataNode;
 import net.ivoa.xml.vospace.v2.Node;
+import net.ivoa.xml.vospace.v2.Param;
 import net.ivoa.xml.vospace.v2.Property;
 import net.ivoa.xml.vospace.v2.Protocol;
 import net.ivoa.xml.vospace.v2.Transfer;
@@ -66,7 +67,7 @@ public class UriServiceTest {
 
     @MockBean
     private CreateNodeService createNodeService;
-    
+
     @MockBean
     private FileServiceClient fileServiceClient;
 
@@ -150,7 +151,7 @@ public class UriServiceTest {
 
         assertEquals("http://file-service/mydata1?jobId=job-id&token=<new-token>", negotiatedTransfer.getProtocols().get(0).getEndpoint());
     }
-    
+
     @Test
     public void testPrivateUrlPermissionDenied() {
 
@@ -185,7 +186,7 @@ public class UriServiceTest {
             uriService.getNegotiatedTransfer(job, tr);
         });
     }
-    
+
     @Test
     public void testPrivateUrlNodeBusy() {
 
@@ -199,8 +200,8 @@ public class UriServiceTest {
         readgroup.setUri(NodeProperties.GROUP_READ_URI);
         readgroup.setValue("group1");
         node.getProperties().add(readgroup);
-        
-        node.setBusy(Boolean.TRUE);        
+
+        node.setBusy(Boolean.TRUE);
 
         when(nodeDAO.listNode(eq("/mydata1"))).thenReturn(Optional.of(node));
 
@@ -413,7 +414,7 @@ public class UriServiceTest {
     public void testZipArchiveViewEndpoint() {
         testArchiveViewEndpoint(Views.ZIP_VIEW_URI);
     }
-    
+
     @Test
     public void testInvalidTransferNoProtocols() {
 
@@ -439,12 +440,23 @@ public class UriServiceTest {
 
         Transfer transfer = new Transfer();
         transfer.setDirection("pullFromVoSpace");
-        transfer.setTarget(Arrays.asList("vos://example.com!vospace/file1", "vos://example.com!vospace/file2"));
+        transfer.setTarget(Arrays.asList("vos://example.com!vospace/parent_dir"));
         Protocol protocol = new Protocol();
         protocol.setUri("ivo://ivoa.net/vospace/core#httpget");
         transfer.getProtocols().add(protocol);
         View view = new View();
         view.setUri(viewUri);
+
+        Param param1 = new Param();
+        param1.setUri(viewUri + "/include");
+        param1.setValue("file1");
+        view.getParam().add(param1);
+
+        Param param2 = new Param();
+        param2.setUri(viewUri + "/include");
+        param2.setValue("file2");
+        view.getParam().add(param2);
+
         transfer.setView(view);
 
         JobSummary job = new JobSummary();
@@ -453,8 +465,9 @@ public class UriServiceTest {
         jobInfo.getAny().add(transfer);
         job.setJobInfo(jobInfo);
 
-        mockPublicNode("file1");
-        mockPublicNode("file2");
+        mockPublicNode("parent_dir");
+        mockPublicNode("parent_dir/file1");
+        mockPublicNode("parent_dir/file2");
 
         uriService.getNegotiatedTransfer(job, transfer);
 
-- 
GitLab