diff --git a/database_update.sql b/database_update.sql index bbdfd5623..1fdf8b3db 100644 --- a/database_update.sql +++ b/database_update.sql @@ -35,4 +35,8 @@ alter table VIPAppVersions ADD useBoutiquesForm BOOLEAN; ALTER TABLE VIPUsers DROP COLUMN phone; -- v2.4 +DROP TABLE VIPAccountsGroups; DROP TABLE VIPAccounts; +ALTER TABLE VIPExternalPlatforms ADD upload_url VARCHAR(255); +ALTER TABLE VIPExternalPlatforms ADD keycloak_client_id VARCHAR(255); +ALTER TABLE VIPExternalPlatforms ADD refresh_token_url VARCHAR(255); \ No newline at end of file diff --git a/pom.xml b/pom.xml index 2252d6391..7fbce2eae 100644 --- a/pom.xml +++ b/pom.xml @@ -43,8 +43,8 @@ knowledge of the CeCILL-B license and that you accept its terms. - 2.4.1 - + 2.5 + diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ApiUserBusiness.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ApiUserBusiness.java index ffade4519..2929da18b 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ApiUserBusiness.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ApiUserBusiness.java @@ -11,7 +11,8 @@ import org.springframework.core.env.Environment; import org.springframework.stereotype.Service; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * @author khalilkes service to signup a user in VIP @@ -34,20 +35,25 @@ public ApiUserBusiness(Environment env, ConfigurationBusiness configurationBusin * * @param user * @param comments - * @param applicationName + * @param applicationNames * @throws ApiException */ - public void signup(User user, String comments, String applicationName) throws ApiException { + public void signup(User user, String comments, List applicationNames) throws ApiException { try { - List groups = applicationBusiness.getPublicGroupsForApplication(applicationName); - configurationBusiness - .signup(user, comments, false, true, groups); + Set allGroups = new TreeSet<>(Comparator.comparing(Group::getName)); + for (String applicationName : applicationNames) { + List appGroups = applicationBusiness.getPublicGroupsForApplication(applicationName); + allGroups.addAll(appGroups); + } + configurationBusiness.signup(user, comments, false, true, new ArrayList<>(allGroups)); logger.info("Signing up with the " + user.getEmail()); } catch (BusinessException e) { throw new ApiException("Signing up Error", e); } } + + public void sendResetCode(String email) throws ApiException { try { configurationBusiness.sendResetCode(email); diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/DataApiBusiness.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/DataApiBusiness.java index 640e35f49..424baa8c5 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/DataApiBusiness.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/DataApiBusiness.java @@ -40,6 +40,7 @@ import fr.insalyon.creatis.vip.core.client.bean.Group; import fr.insalyon.creatis.vip.core.client.bean.User; import fr.insalyon.creatis.vip.core.server.business.BusinessException; +import fr.insalyon.creatis.vip.core.server.business.Server; import fr.insalyon.creatis.vip.datamanager.client.bean.Data; import fr.insalyon.creatis.vip.datamanager.client.bean.Data.Type; import fr.insalyon.creatis.vip.datamanager.client.bean.PoolOperation; @@ -92,21 +93,24 @@ public class DataApiBusiness { private final LFCPermissionBusiness lfcPermissionBusiness; private final DataManagerBusiness dataManagerBusiness; - // 2 threads are needed for every download - private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2 * 5); + private final ScheduledExecutorService scheduler; @Autowired public DataApiBusiness( Environment env, Supplier currentUserProvider, LFCBusiness lfcBusiness, TransferPoolBusiness transferPoolBusiness, LFCPermissionBusiness lfcPermissionBusiness, - DataManagerBusiness dataManagerBusiness) { + DataManagerBusiness dataManagerBusiness, Server server) { this.env = env; this.currentUserProvider = currentUserProvider; this.lfcBusiness = lfcBusiness; this.transferPoolBusiness = transferPoolBusiness; this.lfcPermissionBusiness = lfcPermissionBusiness; this.dataManagerBusiness = dataManagerBusiness; + int parallelDownloadsNb = server.getApiParallelDownloadNb(); + logger.info("Starting threads for {} parallel downloads", parallelDownloadsNb); + // 2 threads are needed for every download + this.scheduler = Executors.newScheduledThreadPool(2 * parallelDownloadsNb); } @PreDestroy diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ExecutionBusiness.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ExecutionBusiness.java index db529e4c5..d296709c1 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ExecutionBusiness.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/ExecutionBusiness.java @@ -123,7 +123,8 @@ public Execution getExecution(String executionId, boolean summarize) // Return null if execution doesn't exist or is cleaned (cleaned status is not supported in Carmin) if (s == null || s.getStatus() == SimulationStatus.Cleaned) { - return null; + logger.error("Error accessing invalid execution {}. (is cleaned : {})", executionId, s != null); + throw new ApiException(ApiException.ApiError.INVALID_EXECUTION_ID, executionId); } // Build Carmin's execution object @@ -258,6 +259,7 @@ public String initExecution(Execution execution) inputMap.put(CoreConstants.RESULTS_DIRECTORY_PARAM_NAME, resultsLocation); } + checkInputExecNameIsValid(execution.getName()); return initExecution( execution.getPipelineIdentifier(), inputMap, execution.getTimeout(), diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/PipelineBusiness.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/PipelineBusiness.java index 420c3dc99..2cab3ad52 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/PipelineBusiness.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/business/PipelineBusiness.java @@ -112,6 +112,9 @@ public Pipeline getPipelineWithResultsDirectory(String pipelineId) for (Source s : d.getSources()) { ParameterType sourceType = ParameterType.fromVipType(s.getType()); + if ("flag".equalsIgnoreCase(s.getVipTypeRestriction())) { + sourceType = ParameterType.Boolean; + } PipelineParameter pp = new PipelineParameter(s.getName(), sourceType, s.isOptional(), diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/RegisterUserController.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/RegisterUserController.java index cb63e4b1f..8971fc32f 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/RegisterUserController.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/controller/RegisterUserController.java @@ -55,9 +55,8 @@ public ResponseEntity signup( ); user.setRegistration(new Date()); user.setLastLogin(new Date()); - this.apiUserBusiness.signup(user, signUpUser.getComments(), signUpUser.getApplication()); + this.apiUserBusiness.signup(user, signUpUser.getComments(), signUpUser.getApplications()); return new ResponseEntity(HttpStatus.CREATED); } - } diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/exception/ApiException.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/exception/ApiException.java index 1c863a95c..35d0cd3ca 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/exception/ApiException.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/exception/ApiException.java @@ -57,7 +57,8 @@ public enum ApiError implements VipError{ WRONG_STAT_SERVICE(8011), COUNTRY_UNKNOWN(8012), UNAUTHORIZED_DATA_ACCESS(8013), - WRONG_OIDC_LOGIN(8014); + WRONG_OIDC_LOGIN(8014), + INVALID_EXECUTION_ID(8015); private Integer code; ApiError(Integer code) { this.code = code; } @@ -79,6 +80,7 @@ public enum ApiError implements VipError{ addMessage(ApiError.COUNTRY_UNKNOWN, "Country unknown : {}", 1); addMessage(ApiError.UNAUTHORIZED_DATA_ACCESS, "Unauthorized data access to : {}", 1); addMessage(ApiError.WRONG_OIDC_LOGIN, "The login process encountered an error", 0); + addMessage(ApiError.INVALID_EXECUTION_ID, "No execution available with this id : {}", 1); } public Optional getMessage() { diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/SignUpUserDTO.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/SignUpUserDTO.java index 793926143..bac9dd63c 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/SignUpUserDTO.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/model/SignUpUserDTO.java @@ -3,6 +3,8 @@ import fr.insalyon.creatis.vip.core.client.view.user.UserLevel; import fr.insalyon.creatis.vip.core.client.view.util.CountryCode; +import java.util.List; + /** * @author KhalilKes * @@ -18,12 +20,12 @@ public class SignUpUserDTO { private UserLevel level; private CountryCode countryCode; private String comments; - private String application; + private List applications; public SignUpUserDTO(){ } - public SignUpUserDTO(String firstName, String lastName, String email, String institution, String password, UserLevel level, CountryCode countryCode, String comments, String application) { + public SignUpUserDTO(String firstName, String lastName, String email, String institution, String password, UserLevel level, CountryCode countryCode, String comments, List applications) { this.firstName = firstName; this.lastName = lastName; this.email = email; @@ -32,9 +34,10 @@ public SignUpUserDTO(String firstName, String lastName, String email, String ins this.level = level; this.countryCode = countryCode; this.comments = comments; - this.application = application; + this.applications = applications; } + public String getFirstName() { return firstName; } @@ -99,8 +102,6 @@ public void setComments(String comments) { this.comments = comments; } - public String getApplication() { return application; } - - public void setApplication(String application) { this.application = application;} + public List getApplications() { return applications; } } diff --git a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/security/egi/EgiSecurityClientConfig.java b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/security/egi/EgiSecurityClientConfig.java index 08372930b..7025b3e59 100644 --- a/vip-api/src/main/java/fr/insalyon/creatis/vip/api/security/egi/EgiSecurityClientConfig.java +++ b/vip-api/src/main/java/fr/insalyon/creatis/vip/api/security/egi/EgiSecurityClientConfig.java @@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; import org.springframework.core.env.Environment; import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; @@ -22,7 +23,13 @@ public EgiSecurityClientConfig(Environment env) { this.env = env; } + /* + This needs the properties that could be in vip-api.conf (especially in the test) + For vip-api.conf properties to be loaded, the ApiPropertyInitializer must be run before + Spring is not aware of that, so we must tell him explicitly with @DependsOn + */ @Bean + @DependsOn("apiPropertiesInitializer") public ClientRegistrationRepository clientRegistrationRepository() { return new InMemoryClientRegistrationRepository(this.egiClientRegistration()); } diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/business/ExecutionBusinessTest.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/business/ExecutionBusinessTest.java index fb335579e..9d8a3bdc6 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/business/ExecutionBusinessTest.java +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/business/ExecutionBusinessTest.java @@ -32,13 +32,16 @@ package fr.insalyon.creatis.vip.api.business; import fr.insalyon.creatis.vip.api.exception.ApiException; +import fr.insalyon.creatis.vip.api.model.Execution; import fr.insalyon.creatis.vip.application.client.bean.Simulation; import fr.insalyon.creatis.vip.application.client.view.monitor.SimulationStatus; import fr.insalyon.creatis.vip.application.server.business.WorkflowBusiness; import fr.insalyon.creatis.vip.core.client.bean.User; import fr.insalyon.creatis.vip.core.client.view.user.UserLevel; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; +import org.springframework.util.Assert; import java.util.function.Supplier; @@ -65,7 +68,7 @@ public void checkIfAdminCanAccessAnyExecution() throws Exception { @Test public void checkIfBasicUserCannotAccessAnyExecution() throws Exception { Supplier userSupplier = () -> prepareTestUser(0, false); - Simulation simulation = prepareSimulation(EXEC_ID, 1); // choose a different user + Simulation simulation = prepareRunningSimulation(EXEC_ID, 1); // choose a different user WorkflowBusiness mockedWb = prepareMockedWorkflowBusiness(EXEC_ID, simulation); ExecutionBusiness sut = new ExecutionBusiness(userSupplier, null, mockedWb, null, null, null, null); ApiException apiException = assertThrows(ApiException.class, @@ -77,12 +80,24 @@ public void checkIfBasicUserCannotAccessAnyExecution() throws Exception { @Test public void checkIfBasicUserCanAccessItsExecution() throws Exception { Supplier userSupplier = () -> prepareTestUser(0, false); - Simulation simulation = prepareSimulation(EXEC_ID, 0); // the creator of the execution is the same user + Simulation simulation = prepareRunningSimulation(EXEC_ID, 0); // the creator of the execution is the same user WorkflowBusiness mockedWb = prepareMockedWorkflowBusiness(EXEC_ID, simulation); ExecutionBusiness sut = new ExecutionBusiness(userSupplier, null, mockedWb, null, null, null, null); sut.checkIfUserCanAccessExecution(EXEC_ID); } + @Test + public void checkErrorWhenAccessingACleanedExecution() throws Exception { + Supplier userSupplier = () -> prepareTestUser(0, false); + Simulation simulation = prepareSimulation(EXEC_ID, SimulationStatus.Cleaned, 0); // the creator of the execution is the same user + WorkflowBusiness mockedWb = prepareMockedWorkflowBusiness(EXEC_ID, simulation); + ExecutionBusiness sut = new ExecutionBusiness(userSupplier, null, mockedWb, null, null, null, null); + ApiException ex = Assertions.assertThrows(ApiException.class, () -> sut.getExecution(EXEC_ID, false)); + Assertions.assertTrue(ex.getVipErrorCode().isPresent()); + Assertions.assertEquals(ApiException.ApiError.INVALID_EXECUTION_ID.getCode(), ex.getVipErrorCode().get()); + } + + // UTILS to be externalized later private User prepareTestUser(int userIndex, boolean isAdmin) { @@ -90,10 +105,14 @@ private User prepareTestUser(int userIndex, boolean isAdmin) { isAdmin ? UserLevel.Administrator : UserLevel.Beginner, null); } - private Simulation prepareSimulation(String exedId, int userIndex) { + private Simulation prepareRunningSimulation(String exedId, int userIndex) { + return prepareSimulation(exedId, SimulationStatus.Running, userIndex); + } + + private Simulation prepareSimulation(String exedId, SimulationStatus status, int userIndex) { User creator = prepareTestUser(userIndex, false); return new Simulation(null, null, null, exedId, creator.getFullName(), null, null, - SimulationStatus.Running.name(), null); + status.name(), null); } private WorkflowBusiness prepareMockedWorkflowBusiness(String execId, Simulation simu) throws Exception { diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/business/LFCPermissionBusinessTest.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/business/LFCPermissionBusinessTest.java new file mode 100644 index 000000000..1b6a00c4f --- /dev/null +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/business/LFCPermissionBusinessTest.java @@ -0,0 +1,41 @@ +package fr.insalyon.creatis.vip.api.business; + +import fr.insalyon.creatis.vip.api.data.UserTestUtils; +import fr.insalyon.creatis.vip.core.client.bean.Group; +import fr.insalyon.creatis.vip.core.client.view.CoreConstants; +import fr.insalyon.creatis.vip.core.server.business.BusinessException; +import fr.insalyon.creatis.vip.datamanager.server.business.LFCPermissionBusiness; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +public class LFCPermissionBusinessTest { + + @AfterEach + protected void tearDown() { + // to reset user groups + UserTestUtils.reset(); + } + + @Test + public void testGroupAccess() throws BusinessException { + String groupName="EGI tutorial"; + String path = "/vip/EGI tutorial (group)/inputs"; + Map groups = new HashMap<>(); + UserTestUtils.baseUser1.setGroups(groups); + UserTestUtils.baseUser2.setGroups(groups); + LFCPermissionBusiness sut = new LFCPermissionBusiness(null, null); + + // First, test users does not belong to the group + Assertions.assertFalse(sut.isLFCPathAllowed(UserTestUtils.baseUser1, path, LFCPermissionBusiness.LFCAccessType.UPLOAD, false)); + Assertions.assertFalse(sut.isLFCPathAllowed(UserTestUtils.baseUser2, path, LFCPermissionBusiness.LFCAccessType.UPLOAD, false)); + + // Then, they belong to the group, but baseUser1 is beginner although baseUser2 is advanced + groups.put(new Group(groupName, true, true, true), CoreConstants.GROUP_ROLE.User); + Assertions.assertFalse(sut.isLFCPathAllowed(UserTestUtils.baseUser1, path, LFCPermissionBusiness.LFCAccessType.UPLOAD, false)); + Assertions.assertTrue(sut.isLFCPathAllowed(UserTestUtils.baseUser2, path, LFCPermissionBusiness.LFCAccessType.UPLOAD, false)); + } +} diff --git a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/UserTestUtils.java b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/UserTestUtils.java index 9de2aaa0e..a0fc593a0 100644 --- a/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/UserTestUtils.java +++ b/vip-api/src/test/java/fr/insalyon/creatis/vip/api/data/UserTestUtils.java @@ -38,6 +38,8 @@ import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; import org.springframework.test.web.servlet.request.RequestPostProcessor; +import java.util.Collections; + /** * Created by abonnet on 7/26/16. */ @@ -53,6 +55,10 @@ public class UserTestUtils { static { + reset(); + } + + static public void reset() { baseUser1 = new User("base1", "User1", "baseuser1@test.tst", null, UserLevel.Beginner, null); baseUser1.setFolder("user1"); @@ -61,7 +67,7 @@ public class UserTestUtils { baseUser2.setFolder("user2"); restUser1 = new SignUpUserDTO("base3", "User3", "baseuser3@test.tst", "test", baseUser2Password, - UserLevel.Advanced, null, "test comment", "test applications"); + UserLevel.Advanced, null, "test comment", Collections.singletonList("test applications")); } public static RequestPostProcessor baseUser1() { diff --git a/vip-application-importer/src/main/java/fr/insalyon/creatis/vip/applicationimporter/server/business/VelocityUtils.java b/vip-application-importer/src/main/java/fr/insalyon/creatis/vip/applicationimporter/server/business/VelocityUtils.java index 467537e0b..a078964ab 100644 --- a/vip-application-importer/src/main/java/fr/insalyon/creatis/vip/applicationimporter/server/business/VelocityUtils.java +++ b/vip-application-importer/src/main/java/fr/insalyon/creatis/vip/applicationimporter/server/business/VelocityUtils.java @@ -51,7 +51,7 @@ public class VelocityUtils { private VelocityEngine velocityEngine; - private VelocityUtils() { + public VelocityUtils() { velocityEngine = new VelocityEngine(); velocityEngine.setProperty("resource.loader", "class"); velocityEngine.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); diff --git a/vip-application/pom.xml b/vip-application/pom.xml index 68c2feb08..3c1d8f658 100644 --- a/vip-application/pom.xml +++ b/vip-application/pom.xml @@ -44,8 +44,8 @@ knowledge of the CeCILL-B license and that you accept its terms. vip-application jar VIP-Application - + fr.insalyon.creatis vip-core @@ -122,9 +122,17 @@ knowledge of the CeCILL-B license and that you accept its terms. test-jar test - + + + + apache.snapshots + Apache Snapshot Repository + https://repository.apache.org/snapshots + + + diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/bean/boutiquesTools/BoutiquesOutputFile.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/bean/boutiquesTools/BoutiquesOutputFile.java index 593bb180e..b8e2013e6 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/bean/boutiquesTools/BoutiquesOutputFile.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/bean/boutiquesTools/BoutiquesOutputFile.java @@ -31,6 +31,8 @@ */ package fr.insalyon.creatis.vip.application.client.bean.boutiquesTools; +import java.util.Set; + import com.google.gwt.user.client.rpc.IsSerializable; /** @@ -47,7 +49,9 @@ public class BoutiquesOutputFile implements IsSerializable { private boolean list; private boolean optional; private String commandLineFlag; - + private String pathTemplateStrippedExtensionsString; + + public String getId() { return id; } @@ -80,6 +84,10 @@ public String getCommandLineFlag() { return commandLineFlag; } + public String getPathTemplateStrippedExtensionsString() { + return pathTemplateStrippedExtensionsString; + } + public void setId(String id) { this.id = id; } @@ -112,4 +120,7 @@ public void setCommandLineFlag(String commandLineFlag) { this.commandLineFlag = commandLineFlag; } -} + public void setPathTemplateStrippedExtensionsString(String pathTemplateStrippedExtensionsString) { + this.pathTemplateStrippedExtensionsString = pathTemplateStrippedExtensionsString; + } +} \ No newline at end of file diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/view/boutiquesParsing/BoutiquesParser.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/view/boutiquesParsing/BoutiquesParser.java index a922c9563..4c42cc22a 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/view/boutiquesParsing/BoutiquesParser.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/view/boutiquesParsing/BoutiquesParser.java @@ -4,7 +4,7 @@ import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; import fr.insalyon.creatis.vip.application.client.bean.boutiquesTools.*; - +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -221,6 +221,8 @@ private BoutiquesOutputFile parseBoutiquesOutputFile(JSONObject outputFile) bof.setPathTemplate(getStringValue(outputFile, "path-template", true)); bof.setList(getBooleanValue(outputFile, "list", true)); bof.setOptional(getBooleanValue(outputFile, "optional", true)); + Set stripExtn=getArrayValueAsStringSet(outputFile, "path-template-stripped-extensions", true); + bof.setPathTemplateStrippedExtensionsString(stripExtn == null ? null : String.join(",", stripExtn)); String commandLineFlag = getStringValue(outputFile, "command-line-flag", true); commandLineFlag = commandLineFlag == null ? "" : commandLineFlag; bof.setCommandLineFlag(commandLineFlag); diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/view/monitor/general/InOutContextMenu.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/view/monitor/general/InOutContextMenu.java index 2c903b191..95ad39a0a 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/view/monitor/general/InOutContextMenu.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/client/view/monitor/general/InOutContextMenu.java @@ -96,24 +96,21 @@ public void onClick(MenuItemClickEvent event) { @Override public void onClick(MenuItemClickEvent event) { String folder = node.getName().substring(0, node.getName().lastIndexOf("/")); - BrowserLayout.getInstance().loadData(folder, false); + BrowserLayout.getInstance().loadData(folder, true); DataManagerModule.dataManagerSection.expand(); } }); - if (!node.getType().equals("Simulation")) { - if (node.getName().startsWith(DataManagerConstants.ROOT + "/")) { - ArrayList menuItems = new ArrayList(); - - BrowserContextMenu.addVizualisers(menuItems, node.getName()); - menuItems.add(downloadFileItem); - menuItems.add(jumpToItem); - } else { - this.setItems(downloadFilesItem); - } + if (node.getName().startsWith(DataManagerConstants.ROOT + "/")) { + ArrayList menuItems = new ArrayList(); + BrowserContextMenu.addVizualisers(menuItems, node.getName()); + menuItems.add(downloadFileItem); + menuItems.add(jumpToItem); + this.setItems(menuItems.toArray(new MenuItem[menuItems.size()])); + } else if (!node.getType().equals("Simulation")) { + this.setItems(downloadFilesItem); } } - private void downloadFile(String path) { AsyncCallback callback = new AsyncCallback() { diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/ApplicationBusiness.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/ApplicationBusiness.java index 039696b9a..339564b80 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/ApplicationBusiness.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/ApplicationBusiness.java @@ -91,9 +91,9 @@ public List getApplicationsWithOwner(String email) throws BusinessE public List getPublicApplicationsWithGroups() throws BusinessException { try { - Map allClasses = classDAO.getClasses().stream().collect(Collectors.toMap( - AppClass::getName, appClass -> appClass)); - Map allGroups = groupDAO.getGroups().stream().collect(Collectors.toMap( + Map allClasses = classDAO.getClasses().stream().collect(Collectors.toMap( + AppClass::getName, appClass -> appClass)); + Map allGroups = groupDAO.getGroups().stream().collect(Collectors.toMap( Group::getName, group -> group)); Set allVisibleApplicationNames = applicationDAO.getAllVisibleVersions().stream() .map(AppVersion::getApplicationName).collect(Collectors.toSet()); @@ -111,13 +111,19 @@ public List getPublicApplicationsWithGroups() throws BusinessExcept .map(group -> group.getName()) .collect(Collectors.toSet()); - if (currentAppPublicGroups.isEmpty()){ + List publicClasses = application.getApplicationClasses().stream() + .filter(className -> allClasses.get(className).getGroups().stream() + .map(groupName -> allGroups.get(groupName)) + .anyMatch(Group::isPublicGroup)) + .collect(Collectors.toList()); + + if (currentAppPublicGroups.isEmpty() || publicClasses.isEmpty()){ continue; } applicationsWithGroups.add(new Application( application.getName(), - application.getApplicationClasses(), + publicClasses, application.getOwner(), application.getFullName(), application.getCitation(), diff --git a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/simulation/parser/AbstractWorkflowParser.java b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/simulation/parser/AbstractWorkflowParser.java index bf964cfd6..cf392ca73 100644 --- a/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/simulation/parser/AbstractWorkflowParser.java +++ b/vip-application/src/main/java/fr/insalyon/creatis/vip/application/server/business/simulation/parser/AbstractWorkflowParser.java @@ -41,6 +41,8 @@ import java.io.FileReader; import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; import java.util.ArrayList; import java.util.List; @@ -60,9 +62,17 @@ protected AbstractWorkflowParser() { } public Descriptor parse(String fileName) throws IOException, SAXException { + return parse(new FileReader(fileName)); + } + + public Descriptor parseString(String workflowString) throws IOException, SAXException { + return parse(new StringReader(workflowString)); + } + + private Descriptor parse(Reader workflowReader) throws IOException, SAXException { reader = XMLReaderFactory.createXMLReader(); reader.setContentHandler(this); - reader.parse(new InputSource(new FileReader(fileName))); + reader.parse(new InputSource(workflowReader)); return new Descriptor(sources,description); } diff --git a/vip-application/src/test/java/fr/insalyon/creatis/vip/application/integrationtest/PublicApplicationListIT.java b/vip-application/src/test/java/fr/insalyon/creatis/vip/application/integrationtest/PublicApplicationListIT.java new file mode 100644 index 000000000..9e882d7ee --- /dev/null +++ b/vip-application/src/test/java/fr/insalyon/creatis/vip/application/integrationtest/PublicApplicationListIT.java @@ -0,0 +1,61 @@ +package fr.insalyon.creatis.vip.application.integrationtest; + +import fr.insalyon.creatis.vip.application.client.bean.AppClass; +import fr.insalyon.creatis.vip.application.client.bean.AppVersion; +import fr.insalyon.creatis.vip.application.client.bean.Application; +import fr.insalyon.creatis.vip.application.client.bean.Engine; +import fr.insalyon.creatis.vip.application.client.rpc.ApplicationService; +import fr.insalyon.creatis.vip.application.client.view.ApplicationException; +import fr.insalyon.creatis.vip.application.server.business.ApplicationBusiness; +import fr.insalyon.creatis.vip.application.server.business.ClassBusiness; +import fr.insalyon.creatis.vip.application.server.business.EngineBusiness; +import fr.insalyon.creatis.vip.application.server.rpc.ApplicationServiceImpl; +import fr.insalyon.creatis.vip.core.client.bean.Group; +import fr.insalyon.creatis.vip.core.integrationtest.database.BaseSpringIT; +import fr.insalyon.creatis.vip.core.server.business.BusinessException; +import fr.insalyon.creatis.vip.core.server.business.ConfigurationBusiness; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class PublicApplicationListIT extends BaseSpringIT { + + @Autowired + private ApplicationBusiness applicationBusiness; + @Autowired + private ClassBusiness classBusiness; + @Autowired + private ConfigurationBusiness configurationBusiness; + + @Test + public void shouldNotIncludePrivateGroupsAndClasses() throws BusinessException, ApplicationException { + // prepare test data + Group publicGroup = new Group("public group", true, true, true); + Group privateGroup = new Group("private group", false, true, true); + // classes are not really public/private, but they are linked to public/private groups + // a class is considered private if it is linked only to private groups + AppClass publicClass = new AppClass("public class", Collections.EMPTY_LIST, Collections.singletonList(publicGroup.getName())); + AppClass privateClass = new AppClass("private class", Collections.EMPTY_LIST, Collections.singletonList(privateGroup.getName())); + Application app = new Application("testApp", Arrays.asList(publicClass.getName(), privateClass.getName()), ""); + AppVersion appVersion = new AppVersion(app.getName(), "", null, null, true, false); + // persist data in database + configurationBusiness.addGroup(publicGroup); + configurationBusiness.addGroup(privateGroup); + classBusiness.addClass(privateClass); + classBusiness.addClass(publicClass); + applicationBusiness.add(app); + applicationBusiness.addVersion(appVersion); + + // verify + List publicApplications = applicationBusiness.getPublicApplicationsWithGroups(); + Assertions.assertEquals(1, publicApplications.size()); + Application resultApp = publicApplications.get(0); + Assertions.assertEquals(app.getName(), resultApp.getName()); + Assertions.assertEquals(1, resultApp.getApplicationGroups().size()); + Assertions.assertEquals(1, resultApp.getApplicationClasses().size()); + } +} diff --git a/vip-core/src/main/java/fr/insalyon/creatis/vip/core/client/view/CoreConstants.java b/vip-core/src/main/java/fr/insalyon/creatis/vip/core/client/view/CoreConstants.java index 29671a2d6..58a83ecf1 100644 --- a/vip-core/src/main/java/fr/insalyon/creatis/vip/core/client/view/CoreConstants.java +++ b/vip-core/src/main/java/fr/insalyon/creatis/vip/core/client/view/CoreConstants.java @@ -41,7 +41,7 @@ public class CoreConstants implements IsSerializable { - public static final String VERSION = "v2.4.1"; + public static final String VERSION = "v2.5"; // Configuration Labels public static final String VO_NAME = "vo.name"; public static final String VO_ROOT = "vo.root"; @@ -188,6 +188,8 @@ public class CoreConstants implements IsSerializable { public static final String GIRDER_TOKEN_DURATION_IN_DAYS = "girder.token.duration-in-days"; // Local config public static final String USE_LOCAL_FILES_AS_INPUTS = "execution.input.local-files"; + // API + public static final String API_PARALLEL_DOWNLOAD_NB = "api.downloads.nb"; public static enum GROUP_ROLE implements IsSerializable { diff --git a/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/business/Server.java b/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/business/Server.java index 484b87d1b..87565d257 100644 --- a/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/business/Server.java +++ b/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/business/Server.java @@ -109,4 +109,6 @@ public interface Server { float getGirderTokenDurationInDays(); boolean useLocalFilesInInputs(); + + int getApiParallelDownloadNb(); } diff --git a/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/business/SpringConfigServer.java b/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/business/SpringConfigServer.java index 1fa4d92dd..a9ef1dda4 100644 --- a/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/business/SpringConfigServer.java +++ b/vip-core/src/main/java/fr/insalyon/creatis/vip/core/server/business/SpringConfigServer.java @@ -430,5 +430,10 @@ public boolean useLocalFilesInInputs() { return env.getProperty(CoreConstants.USE_LOCAL_FILES_AS_INPUTS, Boolean.class, false); } + @Override + public int getApiParallelDownloadNb() { + return env.getProperty(CoreConstants.API_PARALLEL_DOWNLOAD_NB, Integer.class, 20); + } + } diff --git a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/bean/ExternalPlatform.java b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/bean/ExternalPlatform.java index b24def9da..97a33050d 100644 --- a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/bean/ExternalPlatform.java +++ b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/bean/ExternalPlatform.java @@ -40,7 +40,8 @@ public class ExternalPlatform { public enum Type { GIRDER, - SHANOIR + SHANOIR, + SRM } private String identifier; diff --git a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/browser/BrowserLayout.java b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/browser/BrowserLayout.java index bde94b818..a1c32e4b7 100644 --- a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/browser/BrowserLayout.java +++ b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/browser/BrowserLayout.java @@ -31,6 +31,7 @@ */ package fr.insalyon.creatis.vip.datamanager.client.view.browser; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.NamedFrame; import com.smartgwt.client.types.Overflow; import com.smartgwt.client.types.SelectionAppearance; @@ -43,10 +44,14 @@ import com.smartgwt.client.widgets.grid.events.CellDoubleClickHandler; import com.smartgwt.client.widgets.layout.VLayout; import fr.insalyon.creatis.vip.core.client.view.ModalWindow; +import fr.insalyon.creatis.vip.core.client.view.layout.Layout; import fr.insalyon.creatis.vip.datamanager.client.DataManagerConstants; import fr.insalyon.creatis.vip.datamanager.client.view.common.BrowserUtil; import fr.insalyon.creatis.vip.datamanager.client.view.operation.OperationLayout; +import java.util.Arrays; +import java.util.List; + /** * * @author Rafael Silva @@ -79,7 +84,7 @@ private BrowserLayout() { this.setOverflow(Overflow.AUTO); this.setShowResizeBar(true); - grid = BrowserUtil.getListGrid(); + this.grid = BrowserUtil.getListGrid(); configureGrid(); modal = new ModalWindow(grid); @@ -158,11 +163,21 @@ public void uploadComplete(String result) { dataUploadWindow = null; } modal.hide(); - for (String operationID : result.split("##")) { - if (!operationID.isEmpty()) { - OperationLayout.getInstance().addOperation(operationID); + + AsyncCallback callback = new AsyncCallback() { + @Override + public void onFailure(Throwable caught) {} // cannot be called + + @Override + public void onSuccess(Void v) { + loadData(toolStrip.getPath(), true); } - } + }; + + String[] operationsIds = result.split("##"); + + OperationLayout.getInstance().addOperationsWithCallback(operationsIds, callback); + } private native void initComplete(BrowserLayout upload) /*-{ diff --git a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/operation/OperationBoxLayout.java b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/operation/OperationBoxLayout.java index a6d4650c6..c1ee74ac4 100644 --- a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/operation/OperationBoxLayout.java +++ b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/operation/OperationBoxLayout.java @@ -54,6 +54,9 @@ import fr.insalyon.creatis.vip.datamanager.client.rpc.DataManagerService; import fr.insalyon.creatis.vip.datamanager.client.rpc.DataManagerServiceAsync; +import java.util.Arrays; +import java.util.List; + /** * * @author Rafael Ferreira da Silva @@ -65,6 +68,7 @@ public class OperationBoxLayout extends HLayout { private VLayout imgLayout; private VLayout mainLayout; private VLayout actionLayout; + private AsyncCallback callback; public OperationBoxLayout(PoolOperation operation) { @@ -104,6 +108,12 @@ public void run() { setTimer(); } + public OperationBoxLayout(PoolOperation operation, final AsyncCallback callback) { + this(operation); + this.callback = callback; + } + + /** * Configures the image layout. */ @@ -275,12 +285,16 @@ public void onSuccess(PoolOperation result) { if (operation.getStatus() == Status.Done || operation.getStatus() == Status.Failed) { - timer.cancel(); - } else { setTimer(); } + + if (operation.getStatus() == Status.Done) { + if (callback != null) { + callback.onSuccess(null); + } + } } }; service.getPoolOperationById(operation.getId(), asyncCallback); diff --git a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/operation/OperationLayout.java b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/operation/OperationLayout.java index b59553d0e..df215052d 100644 --- a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/operation/OperationLayout.java +++ b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/client/view/operation/OperationLayout.java @@ -31,6 +31,7 @@ */ package fr.insalyon.creatis.vip.datamanager.client.view.operation; +import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; import com.smartgwt.client.types.Overflow; import com.smartgwt.client.types.VerticalAlignment; @@ -42,8 +43,14 @@ import fr.insalyon.creatis.vip.datamanager.client.bean.PoolOperation; import fr.insalyon.creatis.vip.datamanager.client.rpc.DataManagerService; import fr.insalyon.creatis.vip.datamanager.client.rpc.DataManagerServiceAsync; + +import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Semaphore; +import java.util.function.Supplier; + /** * @@ -182,6 +189,55 @@ public void onSuccess(PoolOperation result) { service.getPoolOperationById(operationID, asyncCallback); } + public void addOperationsWithCallback(String[] operationsIds, AsyncCallback callback) { + if (operationsIds.length == 1) { + addOperationWithCallback(operationsIds[0], callback); + return; + } + AsyncCallback counterCallback = new AsyncCallback() { + Integer counter = operationsIds.length; + @Override + public void onFailure(Throwable caught) {} // cannot be called + + @Override + public void onSuccess(Void v) { + counter--; + if (counter == 0) { + callback.onSuccess(null); + } + } + }; + + DataManagerServiceAsync service = DataManagerService.Util.getInstance(); + for (String operationID : operationsIds) { + service.getPoolOperationById(operationID, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + Layout.getInstance().setWarningMessage(operationID + "
Unable to get operation data:
" + caught.getMessage()); + } + + @Override + public void onSuccess(PoolOperation result) { + operationsLayout.addMember(new OperationBoxLayout(result, counterCallback), 0); + } + }); + } + } + + public void addOperationWithCallback(String operationID, AsyncCallback callback) { + DataManagerService.Util.getInstance().getPoolOperationById(operationID, new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + Layout.getInstance().setWarningMessage(operationID + "
Unable to get operation data:
" + caught.getMessage()); + } + + @Override + public void onSuccess(PoolOperation result) { + operationsLayout.addMember(new OperationBoxLayout(result, callback), 0); + } + }); + } + /** * Removes all operations from the list. */ diff --git a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/business/ExternalPlatformBusiness.java b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/business/ExternalPlatformBusiness.java index 2195e4c4f..a4939de3f 100644 --- a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/business/ExternalPlatformBusiness.java +++ b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/business/ExternalPlatformBusiness.java @@ -56,15 +56,18 @@ public class ExternalPlatformBusiness { private GirderStorageBusiness girderStorageBusiness; private ShanoirStorageBusiness shanoirStorageBusiness; + private SrmStorageBusiness srmStorageBusiness; private ExternalPlatformsDAO externalPlatformsDAO; @Autowired public ExternalPlatformBusiness( GirderStorageBusiness girderStorageBusiness, ShanoirStorageBusiness shanoirStorageBusiness, + SrmStorageBusiness srmStorageBusiness, ExternalPlatformsDAO externalPlatformsDAO) { this.girderStorageBusiness = girderStorageBusiness; this.shanoirStorageBusiness = shanoirStorageBusiness; + this.srmStorageBusiness = srmStorageBusiness; this.externalPlatformsDAO = externalPlatformsDAO; } @@ -118,8 +121,12 @@ public ParseResult parseParameter( externalPlatform, parameterName, parameterValue ); return new ParseResult(true, shanoirUri); + case SRM: + String srmUri = srmStorageBusiness.generateUri(externalPlatform, + fileIdentifier, user); + return new ParseResult(true, srmUri); default: - String error = "Only girder external storage are supported. " + String error = "Only girder, shanoir and srm external storages are supported. " + " (found : " + externalPlatform.getType() + " )"; logger.error(error); throw new BusinessException(error); diff --git a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/business/SrmStorageBusiness.java b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/business/SrmStorageBusiness.java new file mode 100644 index 000000000..198c5d47f --- /dev/null +++ b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/business/SrmStorageBusiness.java @@ -0,0 +1,86 @@ +/* + * Copyright and authors: see LICENSE.txt in base repository. + * + * This software is a web portal for pipeline execution on distributed systems. + * + * This software is governed by the CeCILL-B license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-B + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-B license and that you accept its terms. + */ +package fr.insalyon.creatis.vip.datamanager.server.business; + +import fr.insalyon.creatis.vip.datamanager.client.DataManagerConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import fr.insalyon.creatis.vip.core.client.bean.User; +import fr.insalyon.creatis.vip.core.server.business.BusinessException; +import fr.insalyon.creatis.vip.datamanager.client.view.DataManagerException; +import fr.insalyon.creatis.vip.datamanager.client.bean.ExternalPlatform; +import fr.insalyon.creatis.vip.datamanager.client.bean.ExternalPlatform.Type; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * Created by Sandesh Patil on 02/07/23(MM/DD/YY). + */ +@Service +@Transactional +public class SrmStorageBusiness { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private LfcPathsBusiness lfcPathsBusiness; + + @Autowired + public SrmStorageBusiness(LfcPathsBusiness lfcPathsBusiness) { + this.lfcPathsBusiness = lfcPathsBusiness; + } + + public String generateUri(ExternalPlatform externalPlatform, String fileIdentifier, User user) throws BusinessException { + verifyExternalPlatform(externalPlatform); + String userFolderPath = ""; + try { + userFolderPath = lfcPathsBusiness.parseBaseDir(user, fileIdentifier); + } catch (DataManagerException e) { + throw new BusinessException(e); + } + return buildUri(externalPlatform.getUrl(), userFolderPath); + } + + private void verifyExternalPlatform(ExternalPlatform externalPlatform) throws BusinessException { + if (!externalPlatform.getType().equals(Type.SRM)) { + logger.error("Trying to generate a srm URI for a non srm storage {}", externalPlatform.getType()); + throw new BusinessException("Cannot generate srm uri"); + } + if (externalPlatform.getUrl() == null) { + logger.error("A srm external storage must have an URL to generate an URI"); + throw new BusinessException("Cannot generate srm uri"); + } + } + private String buildUri(String apiUrl, String userFolderPath) { + return apiUrl + "/" + (DataManagerConstants.USERS_HOME).toLowerCase() + userFolderPath; + } +} diff --git a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/rpc/FileUploadServiceImpl.java b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/rpc/FileUploadServiceImpl.java index 18b54d080..3be2fa471 100644 --- a/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/rpc/FileUploadServiceImpl.java +++ b/vip-datamanagement/src/main/java/fr/insalyon/creatis/vip/datamanager/server/rpc/FileUploadServiceImpl.java @@ -156,6 +156,9 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) String dir = uploadedFile.getParent(); uploadedFile.delete(); operationID = processDir(user, dir, path, usePool); + if (operationID.endsWith("##")) { + operationID = operationID.substring(0, operationID.length() - 2); + } } } else { @@ -191,7 +194,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) } private String processDir(User user, String dir, String baseDir, boolean usePool) - throws GRIDAClientException, DataManagerException { + throws GRIDAClientException, DataManagerException { StringBuilder ids = new StringBuilder(); for (File f : new File(dir).listFiles()) { @@ -204,11 +207,12 @@ private String processDir(User user, String dir, String baseDir, boolean usePool usePool)); } else { ids.append( - uploadFile( - user, f.getAbsolutePath(), baseDir, usePool)); + uploadFile( + user, f.getAbsolutePath(), baseDir, usePool)); + ids.append("##"); } - ids.append("##"); } + return ids.toString(); } diff --git a/vip-portal/src/main/resources/vm/gasw.vm b/vip-portal/src/main/resources/vm/gasw.vm index b4d638d9a..a1afbbabe 100644 --- a/vip-portal/src/main/resources/vm/gasw.vm +++ b/vip-portal/src/main/resources/vm/gasw.vm @@ -31,9 +31,13 @@ #set ($value=$value.replace($input.getValueKey(),"$na$i")) #end #end -