diff --git a/VERSION.txt b/VERSION.txt index 03f4ac328305d953e64f6020bf5ad2a871c188f7..87a4e62a094b0dda061c6e1c46dbaddbb22a3593 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,3 +1,6 @@ +2.3.0 Add training access tokens to sandbox api calls. Add access token endpoint. +2.2.10 Fix user ref creation failing on parallel requests. +2.2.9 Add check to prevent reviving an expired training instance. 2.2.8 Add check for training definition being in use when trying to add, remove and update tasks. 2.2.7 Add more descriptive message when training phase contains no tasks. Add answer required field to Adaptive Question. 2.2.6 Implement the ANSWER tag replacing in task solution. diff --git a/pom.xml b/pom.xml index 5e92154fcd149c2627fcd19a55f3815e8c57adce..668219ba4de7d94be9061c2894d2612269a5cb6a 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ <groupId>cz.muni.ics.kypo</groupId> <artifactId>kypo-adaptive-training</artifactId> - <version>2.2.8</version> + <version>2.3.0</version> <packaging>jar</packaging> <name>KYPO2 Adaptive Training</name> <description>KYPO2 Adaptive Training</description> diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/controller/TrainingInstancesRestController.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/controller/TrainingInstancesRestController.java index c39917f88af900613ceb44c2b58f5847fbdbcc5f..b6c24323080e1b65e07dade11cb58dee72d269de 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/controller/TrainingInstancesRestController.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/controller/TrainingInstancesRestController.java @@ -86,6 +86,32 @@ public class TrainingInstancesRestController { return ResponseEntity.ok(trainingInstanceResource); } + /** + * Get Training instance access token by pool id. + * + * @param poolId id of the assigned pool. + * @return Requested access token by pool id if it exists. + */ + @ApiOperation(httpMethod = "GET", + value = "Get training instance access token by pool id.", + response = String.class, + nickname = "findTrainingInstanceAccessTokenByPoolId", + notes = "Returns training instance access token by pool id.", + produces = MediaType.APPLICATION_JSON_VALUE + ) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "The access token has been found", response = TrainingInstanceDTO.class), + @ApiResponse(code = 404, message = "The access token has not been found.", response = ApiError.class), + @ApiResponse(code = 500, message = "Unexpected condition was encountered.", response = ApiError.class) + }) + @GetMapping(path = "/access/{poolId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<String> findInstanceAccessTokenByPoolId( + @ApiParam(value = "Pool ID", required = true) + @PathVariable("poolId") Long poolId) { + String accessToken = trainingInstanceFacade.findInstanceAccessTokenByPoolId(poolId); + return ResponseEntity.ok(accessToken); + } + /** * Get all Training Instances. * @@ -107,7 +133,7 @@ public class TrainingInstancesRestController { @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Object> findAllTrainingInstances(@QuerydslPredicate(root = TrainingInstance.class) Predicate predicate, @ApiParam(value = "Pagination support.", required = false) - Pageable pageable, + Pageable pageable, @ApiParam(value = "Fields which should be returned in REST API response", required = false) @RequestParam(value = "fields", required = false) String fields) { PageResultResource<TrainingInstanceFindAllResponseDTO> trainingInstanceResource = trainingInstanceFacade.findAll(predicate, pageable); @@ -275,7 +301,7 @@ public class TrainingInstancesRestController { @ApiParam(value = "If only active or not active training runs should be returned.") @RequestParam(value = "isActive", required = false) Boolean isActive, @ApiParam(value = "Pagination support.") - Pageable pageable, + Pageable pageable, @ApiParam(value = "Fields which should be returned in REST API response", required = false) @RequestParam(value = "fields", required = false) String fields) { PageResultResource<TrainingRunDTO> trainingRunResource = trainingInstanceFacade.findTrainingRunsByTrainingInstance(instanceId, isActive, pageable); @@ -312,7 +338,7 @@ public class TrainingInstancesRestController { @ApiParam(value = "Family name filter.", required = true) @RequestParam(value = "familyName", required = false) String familyName, @ApiParam(value = "Pagination support.") - Pageable pageable) { + Pageable pageable) { PageResultResource<UserRefDTO> designers = trainingInstanceFacade.getOrganizersOfTrainingInstance(trainingInstanceId, pageable, givenName, familyName); return ResponseEntity.ok(SquigglyUtils.stringify(objectMapper, designers)); } @@ -347,7 +373,7 @@ public class TrainingInstancesRestController { @ApiParam(value = "Family name filter.", required = false) @RequestParam(value = "familyName", required = false) String familyName, @ApiParam(value = "Pagination support.") - Pageable pageable) { + Pageable pageable) { PageResultResource<UserRefDTO> designers = trainingInstanceFacade.getOrganizersNotInGivenTrainingInstance(trainingInstanceId, pageable, givenName, familyName); return ResponseEntity.ok(SquigglyUtils.stringify(objectMapper, designers)); } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java index 85f306716b7f622a0bb1f1d357ec2187fdf564a6..7a03dc311b6e8e967f2a4c7bf950c2d7967142fa 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/domain/training/TrainingInstance.java @@ -57,6 +57,11 @@ import java.util.Set; "LEFT OUTER JOIN FETCH td.authors " + "WHERE ti.id = :instanceId" ), + @NamedQuery( + name = "TrainingInstance.findByPoolId", + query = "SELECT ti FROM TrainingInstance ti " + + "WHERE ti.poolId = :poolId" + ), @NamedQuery( name = "TrainingInstance.findAllByTrainingDefinitionId", query = "SELECT ti FROM TrainingInstance ti JOIN FETCH ti.trainingDefinition td WHERE td.id = :trainingDefId" diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingDefinitionFacade.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingDefinitionFacade.java index 9dff1a6bb0859642307b60a3c3d13d952e36d6ef..16c76509ed1721f7068444f7208e55814ef2d8bf 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingDefinitionFacade.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingDefinitionFacade.java @@ -219,12 +219,6 @@ public class TrainingDefinitionFacade { trainingDefinitionService.update(mappedTrainingDefinition); } - private User createUserRefFromDTO(UserRefDTO userToBeCreated) { - User user = new User(); - user.setUserRefId(userToBeCreated.getUserRefId()); - return user; - } - /** * Clones Training Definition by id * @@ -359,11 +353,8 @@ public class TrainingDefinitionFacade { if (actualAuthorsIds.contains(author.getUserRefId())) { continue; } - try { - trainingDefinition.addAuthor(userService.getUserByUserRefId(author.getUserRefId())); - } catch (EntityNotFoundException ex) { - trainingDefinition.addAuthor(userService.createUserRef(createUserRefFromDTO(author))); - } + User user = userService.createOrGetUserRef(author.getUserRefId()); + trainingDefinition.addAuthor(user); } } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java index 26a530561a2de43d4c72ada4c456e3b43f88147f..60e6689063d2b4047705d8091117c89741e39433 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/facade/TrainingInstanceFacade.java @@ -106,6 +106,18 @@ public class TrainingInstanceFacade { return trainingInstanceMapper.mapToDTO(trainingInstanceService.findByIdIncludingDefinition(id)); } + /** + * Get Training instance access token by pool id. + * + * @param poolId id of the assigned pool. + * @return Requested access token by pool id if it exists. + */ + @IsOrganizerOrAdmin + @TransactionalRO + public String findInstanceAccessTokenByPoolId(Long poolId) { + return trainingInstanceService.findInstanceAccessTokenByPoolId(poolId); + } + /** * Find all Training Instances. * @@ -145,21 +157,21 @@ public class TrainingInstanceFacade { Long oldPoolId = trainingInstance.getPoolId(); String accessToken = trainingInstanceService.update(updatedTrainingInstance); if (isPoolIdChanged(oldPoolId, updatedTrainingInstance.getPoolId())) { - handlePoolIdModification(oldPoolId, updatedTrainingInstance.getPoolId()); + handlePoolIdModification(oldPoolId, updatedTrainingInstance.getPoolId(), updatedTrainingInstance.getAccessToken()); } return accessToken; } - private void handlePoolIdModification(Long currentPoolId, Long newPoolId) { + private void handlePoolIdModification(Long currentPoolId, Long newPoolId, String accessToken) { if (currentPoolId == null) { - sandboxServiceApi.lockPool(newPoolId); + sandboxServiceApi.lockPool(newPoolId, accessToken); } else if (newPoolId == null) { sandboxServiceApi.unlockPool(currentPoolId); deleteBashCommandsByPool(currentPoolId); } else { sandboxServiceApi.unlockPool(currentPoolId); deleteBashCommandsByPool(currentPoolId); - sandboxServiceApi.lockPool(newPoolId); + sandboxServiceApi.lockPool(newPoolId, accessToken); } } @@ -182,7 +194,7 @@ public class TrainingInstanceFacade { trainingInstance.setId(null); TrainingInstance createdTrainingInstance = trainingInstanceService.create(trainingInstance); if (trainingInstance.getPoolId() != null) { - handlePoolIdModification(null, trainingInstance.getPoolId()); + handlePoolIdModification(null, trainingInstance.getPoolId(), trainingInstance.getAccessToken()); } return trainingInstanceMapper.mapToDTO(createdTrainingInstance); } @@ -197,11 +209,8 @@ public class TrainingInstanceFacade { if (actualOrganizersIds.contains(organizer.getUserRefId())) { continue; } - try { - trainingInstance.addOrganizer(userService.getUserByUserRefId(organizer.getUserRefId())); - } catch (EntityNotFoundException ex) { - trainingInstance.addOrganizer(userService.createUserRef(createUserRefFromDTO(organizer))); - } + User user = userService.createOrGetUserRef(organizer.getUserRefId()); + trainingInstance.addOrganizer(user); } } @@ -218,12 +227,6 @@ public class TrainingInstanceFacade { return users; } - private User createUserRefFromDTO(UserRefDTO userToBeCreated) { - User user = new User(); - user.setUserRefId(userToBeCreated.getUserRefId()); - return user; - } - /** * Deletes specific training instance based on id * @@ -291,7 +294,7 @@ public class TrainingInstanceFacade { "Training instance already contains pool Id. Please first unassign pool id and then assign another pool again.")); } // lock pool and update pool - sandboxServiceApi.lockPool(trainingInstanceAssignPoolIdDTO.getPoolId()); + sandboxServiceApi.lockPool(trainingInstanceAssignPoolIdDTO.getPoolId(), trainingInstance.getAccessToken()); trainingInstance.setPoolId(trainingInstanceAssignPoolIdDTO.getPoolId()); return trainingInstanceMapper.mapEntityToTIBasicInfo(trainingInstanceService.auditAndSave(trainingInstance)); } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepository.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepository.java index c44943f6b5b8a2978911a320b083a0338ded996f..f42c7f7dbd3db113c4f32d97cd9efcfec1c3d4b2 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepository.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepository.java @@ -13,7 +13,7 @@ import java.util.Set; * The JPA repository interface to manage {@link User} instances. */ @Repository -public interface UserRefRepository extends JpaRepository<User, Long>, QuerydslPredicateExecutor<User> { +public interface UserRefRepository extends JpaRepository<User, Long>, QuerydslPredicateExecutor<User>, UserRefRepositoryCustom { /** * Find all users by userRefIds. diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryCustom.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryCustom.java new file mode 100644 index 0000000000000000000000000000000000000000..158c52862c4f19cf7a3a7c0704c070da72b59ce6 --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryCustom.java @@ -0,0 +1,22 @@ +package cz.muni.ics.kypo.training.adaptive.repository; + +import cz.muni.ics.kypo.training.adaptive.domain.User; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.repository.query.Param; + +import javax.transaction.Transactional; + + +public interface UserRefRepositoryCustom { + + /** + * Insert user reference if it does not exist in the database. + * + * @param userRefId the user reference id + * @return the number of rows affected + */ + @Modifying + @Transactional + User createOrGet(@Param("userRefId") Long userRefId); + +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryImpl.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..17f3a973b62546df4e0db6d337d5fbdc05eed0c4 --- /dev/null +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/UserRefRepositoryImpl.java @@ -0,0 +1,41 @@ +package cz.muni.ics.kypo.training.adaptive.repository; + +import cz.muni.ics.kypo.training.adaptive.domain.User; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Repository; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +@Repository +public class UserRefRepositoryImpl implements UserRefRepositoryCustom { + + private static final Logger LOG = LoggerFactory.getLogger(UserRefRepositoryImpl.class); + + @PersistenceContext + private EntityManager entityManager; + + @Override + public User createOrGet(Long userRefId) { + int rowsAffected = entityManager.createNativeQuery("INSERT INTO \"user\" (user_ref_id) VALUES (:userRefId)" + + "ON CONFLICT DO NOTHING") + .setParameter("userRefId", userRefId) + .executeUpdate(); + + if (rowsAffected != 0) { + LOG.info("User with user_ref_id {} created", userRefId); + } + + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class); + Root<User> root = criteriaQuery.from(User.class); + criteriaQuery.select(root).where(criteriaBuilder.equal(root.get("userRefId"), userRefId)); + return entityManager.createQuery(criteriaQuery).getSingleResult(); + } + + +} diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/training/TrainingInstanceRepository.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/training/TrainingInstanceRepository.java index 222353680bc4cd3279da6abefbf8d87b906ccf8d..5017272000a840cb06fb1e53247fc2d44439a42f 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/training/TrainingInstanceRepository.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/repository/training/TrainingInstanceRepository.java @@ -76,6 +76,14 @@ public interface TrainingInstanceRepository extends JpaRepository<TrainingInstan ) Optional<TrainingInstance> findById(Long id); + /** + * Find training instance by pool id. + * + * @param poolId the pool id + * @return {@link TrainingInstance} including its associated {@link TrainingDefinition} + */ + Optional<TrainingInstance> findByPoolId(@Param("poolId") Long poolId); + /** * Find training instance with start time in the past, end time in the future and by corresponding access token. * diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/UserService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/UserService.java index 6e78c324412d0ab99f439ef4d2d82c2af610762b..0a8165f796e7826e4bc831bef33ea3e12fb0f920 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/UserService.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/UserService.java @@ -45,15 +45,14 @@ public class UserService { } /** - * Create new user reference + * If user reference with given user id does not exist, it is created and returned. + * Otherwise, the existing one is returned. * - * @param userToCreate user reference to be created - * @return created {@link User} + * @param userRefId id of the referenced user + * @return user reference with given referenced id */ - @TransactionalWO - public User createUserRef(User userToCreate) { - User user = userRefRepository.save(userToCreate); - LOG.info("User ref with user_ref_id: {} created.", user.getUserRefId()); - return user; + public User createOrGetUserRef(Long userRefId) { + return userRefRepository.createOrGet(userRefId); } + } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/api/SandboxServiceApi.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/api/SandboxServiceApi.java index 68fa0c659d5ef431619b1316e27728e4a55a07d9..8503ba6d6b8ab8bafc4461aa2876d417a086b71f 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/api/SandboxServiceApi.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/api/SandboxServiceApi.java @@ -37,11 +37,11 @@ public class SandboxServiceApi { } - public Pair<Integer, String> getAndLockSandboxForTrainingRun(Long poolId) { + public Pair<Integer, String> getAndLockSandboxForTrainingRun(Long poolId, String trainingAccessToken) { try { SandboxInfo sandboxInfo = sandboxServiceWebClient .get() - .uri("/pools/{poolId}/sandboxes/get-and-lock", poolId) + .uri("/pools/{poolId}/sandboxes/get-and-lock/{trainingAccessToken}", poolId, trainingAccessToken) .retrieve() .bodyToMono(SandboxInfo.class) .block(); @@ -58,14 +58,17 @@ public class SandboxServiceApi { * Lock pool locked pool info. * * @param poolId the pool id + * @param accessToken the training access token * @return the locked pool info */ - public LockedPoolInfo lockPool(Long poolId) { + public LockedPoolInfo lockPool(Long poolId, String accessToken) { try { + String requestBody = String.format("{\"training_access_token\": \"%s\"}", accessToken); + return sandboxServiceWebClient .post() .uri("/pools/{poolId}/locks", poolId) - .body(Mono.just("{}"), String.class) + .body(Mono.just(requestBody), String.class) .retrieve() .bodyToMono(LockedPoolInfo.class) .block(); diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingDefinitionService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingDefinitionService.java index 2648a26c8c6e39d74ab45e1fdb3af3803271d1f3..5005ff31179975a9c4a3a6451df55f0f2aae825d 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingDefinitionService.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingDefinitionService.java @@ -456,14 +456,7 @@ public class TrainingDefinitionService { } private void addLoggedInUserToTrainingDefinitionAsAuthor(TrainingDefinition trainingDefinition) { - Long loggedInId = userManagementServiceApi.getLoggedInUserRefId(); - Optional<User> user = userRefRepository.findUserByUserRefId(loggedInId); - if (user.isPresent()) { - trainingDefinition.addAuthor(user.get()); - } else { - User newUser = new User(loggedInId); - userRefRepository.saveAndFlush(newUser); - trainingDefinition.addAuthor(newUser); - } + User user = userRefRepository.createOrGet(userManagementServiceApi.getLoggedInUserRefId()); + trainingDefinition.addAuthor(user); } } diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java index 7aebe488c9409795ccaedd4256be1d248878d55a..ea7b53d7b6a4d4a06d4e3f25909bffa009c4e078 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingInstanceService.java @@ -74,6 +74,17 @@ public class TrainingInstanceService { .orElseThrow(() -> new EntityNotFoundException(new EntityErrorDetail(TrainingInstance.class, "id", instanceId.getClass(), instanceId))); } + /** + * Find Training instance access token by pool id if exists. + * + * @param poolId the pool id + * @return the access token + */ + public String findInstanceAccessTokenByPoolId(Long poolId) { + Optional<TrainingInstance> instance = trainingInstanceRepository.findByPoolId(poolId); + return instance.map(TrainingInstance::getAccessToken).orElse(null); + } + /** * Find specific Training instance by id including its associated Training definition. * @@ -135,6 +146,7 @@ public class TrainingInstanceService { public String update(TrainingInstance trainingInstanceToUpdate) { validateStartAndEndTime(trainingInstanceToUpdate); TrainingInstance trainingInstance = findById(trainingInstanceToUpdate.getId()); + checkNotRevivingAnExpiredInstance(trainingInstanceToUpdate, trainingInstance); //add original organizers to update trainingInstanceToUpdate.setOrganizers(new HashSet<>(trainingInstance.getOrganizers())); addLoggedInUserAsOrganizerToTrainingInstance(trainingInstanceToUpdate); @@ -176,6 +188,14 @@ public class TrainingInstanceService { } } + private void checkNotRevivingAnExpiredInstance(TrainingInstance trainingInstanceToUpdate, TrainingInstance currentTrainingInstance) { + if (currentTrainingInstance.finished() && !trainingInstanceToUpdate.finished()) { + throw new EntityConflictException(new EntityErrorDetail(TrainingInstance.class, "id", + trainingInstanceToUpdate.getId().getClass(), trainingInstanceToUpdate.getId(), + "End time of an expired instance cannot be set to the future.")); + } + } + private void checkChangedFieldsOfTrainingInstance(TrainingInstance trainingInstanceToUpdate, TrainingInstance currentTrainingInstance) { if (!currentTrainingInstance.getStartTime().equals(trainingInstanceToUpdate.getStartTime())) { throw new EntityConflictException(new EntityErrorDetail(TrainingInstance.class, "id", Long.class, trainingInstanceToUpdate.getId(), @@ -214,13 +234,8 @@ public class TrainingInstanceService { } private void addLoggedInUserAsOrganizerToTrainingInstance(TrainingInstance trainingInstance) { - Optional<User> authorOfTrainingInstance = organizerRefRepository.findUserByUserRefId(userManagementServiceApi.getLoggedInUserRefId()); - if (authorOfTrainingInstance.isPresent()) { - trainingInstance.addOrganizer(authorOfTrainingInstance.get()); - } else { - User user = new User(userManagementServiceApi.getLoggedInUserRefId()); - trainingInstance.addOrganizer(organizerRefRepository.save(user)); - } + User userRef = organizerRefRepository.createOrGet(userManagementServiceApi.getLoggedInUserRefId()); + trainingInstance.addOrganizer(userRef); } /** diff --git a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java index 797c046334b271d10b7c643386ff4d048fd1a067..e226d8c1467d77e5dd67d509b6036bdcc78b3b7c 100644 --- a/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java +++ b/src/main/java/cz/muni/ics/kypo/training/adaptive/service/training/TrainingRunService.java @@ -191,10 +191,10 @@ public class TrainingRunService { } /** - * Checks whether any trainin runs exists for particular training instance + * Checks whether any training runs exists for particular training instance * * @param trainingInstanceId the training instance id - * @return boolean boolean + * @return boolean */ public boolean existsAnyForTrainingInstance(Long trainingInstanceId) { return trainingRunRepository.existsAnyForTrainingInstance(trainingInstanceId); @@ -202,7 +202,7 @@ public class TrainingRunService { /** - * Finds all Training Runs of logged in user. + * Finds all Training Runs of logged-in user. * * @param pageable pageable parameter with information about pagination. * @return {@link TrainingRun}s of logged in user. @@ -279,7 +279,8 @@ public class TrainingRunService { AdaptiveSmartAssistantInput smartAssistantInput = this.gatherInputDataForSmartAssistant(trainingRun, (TrainingPhase) nextPhase, phases); String accessToken = trainingRun.getTrainingInstance().getAccessToken(); Long userId = trainingRun.getParticipantRef().getUserRefId(); - // smart assistant returns order of the tasks counted from 1 and we need to decrease the number by 1, since Java order collections from 0 + // smart assistant returns order of the tasks counted from 1, and we need to decrease the number by 1, + // since Java order collections from 0 int suitableTask = this.smartAssistantServiceApi.findSuitableTaskInPhase(smartAssistantInput, accessToken, userId).getSuitableTask(); trainingRun.setCurrentTask(((TrainingPhase) nextPhase).getTasks().get(suitableTask - 1)); } else { @@ -465,11 +466,11 @@ public class TrainingRunService { } /** - * Finds all Training Runs of specific Training Definition of logged in user. + * Finds all Training Runs of specific Training Definition of logged-in user. * * @param definitionId id of Training Definition * @param pageable pageable parameter with information about pagination. - * @return {@link TrainingRun}s of specific Training Definition of logged in user + * @return {@link TrainingRun}s of specific Training Definition of logged-in user */ public Page<TrainingRun> findAllByTrainingDefinitionAndParticipant(Long definitionId, Pageable pageable) { return trainingRunRepository.findAllByTrainingDefinitionIdAndParticipantUserRefId(definitionId, userManagementServiceApi.getLoggedInUserRefId(), pageable); @@ -589,12 +590,9 @@ public class TrainingRunService { TrainingRun newTrainingRun = new TrainingRun(); newTrainingRun.setCurrentPhase(currentPhase); - Optional<User> userRefOpt = participantRefRepository.findUserByUserRefId(participantRefId); - if (userRefOpt.isPresent()) { - newTrainingRun.setParticipantRef(userRefOpt.get()); - } else { - newTrainingRun.setParticipantRef(participantRefRepository.save(new User(userManagementServiceApi.getLoggedInUserRefId()))); - } + User userRef = participantRefRepository.createOrGet(participantRefId); + newTrainingRun.setParticipantRef(userRef); + newTrainingRun.setState(TRState.RUNNING); newTrainingRun.setTrainingInstance(trainingInstance); newTrainingRun.setStartTime(startTime); @@ -612,7 +610,7 @@ public class TrainingRunService { * @throws MicroserviceApiException error calling OpenStack Sandbox Service API */ public TrainingRun assignSandbox(TrainingRun trainingRun, long poolId) { - Pair<Integer, String> sandboxRefAndId = this.sandboxServiceApi.getAndLockSandboxForTrainingRun(poolId); + Pair<Integer, String> sandboxRefAndId = this.sandboxServiceApi.getAndLockSandboxForTrainingRun(poolId, trainingRun.getTrainingInstance().getAccessToken()); trainingRun.setSandboxInstanceRefId(sandboxRefAndId.getRight()); trainingRun.setSandboxInstanceAllocationId(sandboxRefAndId.getLeft()); return trainingRunRepository.save(trainingRun); diff --git a/src/main/resources/db/migration/V14__db_make_user_ref_id_unique.sql b/src/main/resources/db/migration/V14__db_make_user_ref_id_unique.sql new file mode 100644 index 0000000000000000000000000000000000000000..66343f96e9cc695ad7053ca6bf7de564c4650049 --- /dev/null +++ b/src/main/resources/db/migration/V14__db_make_user_ref_id_unique.sql @@ -0,0 +1 @@ +alter table "user" add constraint user_ref_id_unique unique (user_ref_id); \ No newline at end of file