Skip to content

Commit

Permalink
Release 2.5 (PR #435 from virtual-imaging-platform/develop)
Browse files Browse the repository at this point in the history
  • Loading branch information
axlbonnet authored Jul 14, 2023
2 parents 820a51b + 0faf399 commit b62c908
Show file tree
Hide file tree
Showing 40 changed files with 576 additions and 99 deletions.
4 changes: 4 additions & 0 deletions database_update.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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);
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ knowledge of the CeCILL-B license and that you accept its terms.
<properties>
<!-- project version. Only to change it here (and in CoreConstants.java
Follow this practice : https://maven.apache.org/maven-ci-friendly.html-->
<revision>2.4.1</revision>
<changelist></changelist>
<revision>2.5</revision>
<changelist/>
<sha1/>

<!-- other maven config -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<String> applicationNames) throws ApiException {
try {
List<Group> groups = applicationBusiness.getPublicGroupsForApplication(applicationName);
configurationBusiness
.signup(user, comments, false, true, groups);
Set<Group> allGroups = new TreeSet<>(Comparator.comparing(Group::getName));
for (String applicationName : applicationNames) {
List<Group> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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<User> 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand All @@ -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<String> getMessage() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -18,12 +20,12 @@ public class SignUpUserDTO {
private UserLevel level;
private CountryCode countryCode;
private String comments;
private String application;
private List<String> 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<String> applications) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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<String> getApplications() { return applications; }

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -65,7 +68,7 @@ public void checkIfAdminCanAccessAnyExecution() throws Exception {
@Test
public void checkIfBasicUserCannotAccessAnyExecution() throws Exception {
Supplier<User> 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,
Expand All @@ -77,23 +80,39 @@ public void checkIfBasicUserCannotAccessAnyExecution() throws Exception {
@Test
public void checkIfBasicUserCanAccessItsExecution() throws Exception {
Supplier<User> 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<User> 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) {
return new User(USER_FIRST_NAME[userIndex], USER_LAST_NAME[userIndex], USER_MAIL[userIndex], null,
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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Group, CoreConstants.GROUP_ROLE> 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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -53,6 +55,10 @@ public class UserTestUtils {


static {
reset();
}

static public void reset() {
baseUser1 = new User("base1", "User1", "[email protected]", null,
UserLevel.Beginner, null);
baseUser1.setFolder("user1");
Expand All @@ -61,7 +67,7 @@ public class UserTestUtils {
baseUser2.setFolder("user2");

restUser1 = new SignUpUserDTO("base3", "User3", "[email protected]", "test", baseUser2Password,
UserLevel.Advanced, null, "test comment", "test applications");
UserLevel.Advanced, null, "test comment", Collections.singletonList("test applications"));
}

public static RequestPostProcessor baseUser1() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Loading

0 comments on commit b62c908

Please sign in to comment.