diff --git a/platform-server-kernel/src/main/java/uno/cod/platform/server/core/service/ResultService.java b/platform-server-kernel/src/main/java/uno/cod/platform/server/core/service/ResultService.java index 839385b7..98546a9f 100644 --- a/platform-server-kernel/src/main/java/uno/cod/platform/server/core/service/ResultService.java +++ b/platform-server-kernel/src/main/java/uno/cod/platform/server/core/service/ResultService.java @@ -10,16 +10,12 @@ import uno.cod.platform.server.core.dto.user.UserShortShowDto; import uno.cod.platform.server.core.exception.CodunoIllegalArgumentException; import uno.cod.platform.server.core.mapper.ResultMapper; -import uno.cod.platform.server.core.repository.ChallengeRepository; -import uno.cod.platform.server.core.repository.ParticipationRepository; -import uno.cod.platform.server.core.repository.ResultRepository; +import uno.cod.platform.server.core.repository.*; +import javax.servlet.http.HttpSession; import javax.transaction.Transactional; import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.UUID; +import java.util.*; @Service @Transactional @@ -28,14 +24,21 @@ public class ResultService { private final ChallengeRepository challengeRepository; private final TaskScheduler taskScheduler; private final ParticipationRepository participationRepository; + private final HttpSession httpSession; + + public static final String CURRENT_CHALLENGE = "CURRENT_CHALLENGE"; @Autowired public ResultService(ResultRepository repository, - ChallengeRepository challengeRepository, TaskScheduler taskScheduler, ParticipationRepository participationRepository) { + ChallengeRepository challengeRepository, + TaskScheduler taskScheduler, + ParticipationRepository participationRepository, + HttpSession httpSession) { this.repository = repository; this.challengeRepository = challengeRepository; this.taskScheduler = taskScheduler; this.participationRepository = participationRepository; + this.httpSession = httpSession; } public ResultShowDto save(UUID challengeId, User user) { @@ -81,6 +84,7 @@ public ResultShowDto save(UUID challengeId, User user) { repository.save(r); }, setFinished); + httpSession.setAttribute(CURRENT_CHALLENGE, challenge.getId()); return ResultMapper.map(result); } @@ -111,6 +115,7 @@ public ResultInfoDto getResultInfoForUserAndChallenge(UUID userId, UUID challeng if (result == null) { return null; } + httpSession.setAttribute(CURRENT_CHALLENGE, challengeId); return new ResultInfoDto(result); } } diff --git a/platform-server-kernel/src/main/java/uno/cod/platform/server/core/service/TaskService.java b/platform-server-kernel/src/main/java/uno/cod/platform/server/core/service/TaskService.java index bb1e7abf..ffcd01b4 100644 --- a/platform-server-kernel/src/main/java/uno/cod/platform/server/core/service/TaskService.java +++ b/platform-server-kernel/src/main/java/uno/cod/platform/server/core/service/TaskService.java @@ -2,19 +2,15 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import uno.cod.platform.server.core.domain.Endpoint; -import uno.cod.platform.server.core.domain.Organization; -import uno.cod.platform.server.core.domain.Runner; -import uno.cod.platform.server.core.domain.Task; +import uno.cod.platform.server.core.domain.*; import uno.cod.platform.server.core.dto.task.TaskCreateDto; import uno.cod.platform.server.core.dto.task.TaskShowDto; +import uno.cod.platform.server.core.exception.CodunoAccessDeniedException; import uno.cod.platform.server.core.exception.CodunoIllegalArgumentException; import uno.cod.platform.server.core.mapper.TaskMapper; -import uno.cod.platform.server.core.repository.EndpointRepository; -import uno.cod.platform.server.core.repository.OrganizationRepository; -import uno.cod.platform.server.core.repository.RunnerRepository; -import uno.cod.platform.server.core.repository.TaskRepository; +import uno.cod.platform.server.core.repository.*; +import javax.servlet.http.HttpSession; import javax.transaction.Transactional; import java.util.List; import java.util.UUID; @@ -26,13 +22,28 @@ public class TaskService { private final EndpointRepository endpointRepository; private final OrganizationRepository organizationRepository; private final RunnerRepository runnerRepository; + private final ChallengeRepository challengeRepository; + private final UserRepository userRepository; + private final ResultRepository resultRepository; + private final HttpSession httpSession; @Autowired - public TaskService(TaskRepository repository, EndpointRepository endpointRepository, OrganizationRepository organizationRepository, RunnerRepository runnerRepository) { + public TaskService(TaskRepository repository, + EndpointRepository endpointRepository, + OrganizationRepository organizationRepository, + RunnerRepository runnerRepository, + ChallengeRepository challengeRepository, + UserRepository userRepository, + ResultRepository resultRepository, + HttpSession httpSession) { this.repository = repository; this.endpointRepository = endpointRepository; this.organizationRepository = organizationRepository; this.runnerRepository = runnerRepository; + this.challengeRepository = challengeRepository; + this.userRepository = userRepository; + this.resultRepository = resultRepository; + this.httpSession = httpSession; } public UUID save(TaskCreateDto dto) { @@ -68,8 +79,28 @@ public UUID save(TaskCreateDto dto) { return repository.save(task).getId(); } - public TaskShowDto findById(UUID id) { - return TaskMapper.map(repository.findOneWithTemplates(id)); + public TaskShowDto findById(UUID taskId, User u) { + Task task = repository.findOneWithTemplates(taskId); + User user = userRepository.findOne(u.getId()); + Object attr = httpSession.getAttribute(ResultService.CURRENT_CHALLENGE); + if (attr == null) { + throw new CodunoAccessDeniedException("challenge.invalid"); + } + + Challenge challenge = challengeRepository.findOne((UUID)attr); + + if (canSeeTask(user, challenge, task)) { + return TaskMapper.map(task); + } + throw new CodunoAccessDeniedException("task.denied"); + } + + private boolean canSeeTask(User user, Challenge challenge, Task task) { + int requestedIndex = challenge.getChallengeTemplate().getTasks().indexOf(task); + + // User can see task if it is the first task (requestedIndex == 0) or the previous task was completed + // successfully. + return requestedIndex == 0 || resultRepository.findOneByUserAndChallenge(user.getId(), challenge.getId()).getTaskResults().get(requestedIndex - 1).isSuccessful(); } public List findAllForOrganization(UUID organizationId) { diff --git a/platform-server-kernel/src/test/java/uno/cod/platform/server/core/service/TaskServiceTest.java b/platform-server-kernel/src/test/java/uno/cod/platform/server/core/service/TaskServiceTest.java index 7fba8e91..9a55fa31 100644 --- a/platform-server-kernel/src/test/java/uno/cod/platform/server/core/service/TaskServiceTest.java +++ b/platform-server-kernel/src/test/java/uno/cod/platform/server/core/service/TaskServiceTest.java @@ -4,15 +4,17 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; -import uno.cod.platform.server.core.domain.Task; +import uno.cod.platform.server.core.domain.*; import uno.cod.platform.server.core.dto.task.TaskCreateDto; import uno.cod.platform.server.core.dto.task.TaskShowDto; -import uno.cod.platform.server.core.repository.EndpointRepository; -import uno.cod.platform.server.core.repository.OrganizationRepository; -import uno.cod.platform.server.core.repository.RunnerRepository; -import uno.cod.platform.server.core.repository.TaskRepository; +import uno.cod.platform.server.core.exception.CodunoAccessDeniedException; +import uno.cod.platform.server.core.repository.*; +import uno.cod.platform.server.core.service.util.ChallengeTestUtil; import uno.cod.platform.server.core.service.util.TaskTestUtil; +import uno.cod.platform.server.core.service.util.UserTestUtil; +import javax.servlet.http.HttpSession; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -23,6 +25,10 @@ public class TaskServiceTest { private EndpointRepository endpointRepository; private OrganizationRepository organizationRepository; private RunnerRepository runnerRepository; + private ChallengeRepository challengeRepository; + private UserRepository userRepository; + private ResultRepository resultRepository; + private HttpSession httpSession; @Before public void setup() { @@ -30,7 +36,11 @@ public void setup() { this.endpointRepository = Mockito.mock(EndpointRepository.class); this.organizationRepository = Mockito.mock(OrganizationRepository.class); this.runnerRepository = Mockito.mock(RunnerRepository.class); - this.service = new TaskService(repository, endpointRepository, organizationRepository, runnerRepository); + this.challengeRepository = Mockito.mock(ChallengeRepository.class); + this.userRepository = Mockito.mock(UserRepository.class); + this.resultRepository = Mockito.mock(ResultRepository.class); + this.httpSession = Mockito.mock(HttpSession.class); + this.service = new TaskService(repository, endpointRepository, organizationRepository, runnerRepository, challengeRepository, userRepository, resultRepository, httpSession); } @Test @@ -48,16 +58,57 @@ public void save() throws Exception { Assert.assertEquals(id, task.getId()); } - @Test - public void findById() throws Exception { + + @Test(expected = CodunoAccessDeniedException.class) + public void findByIdAccessDenied() throws Exception { + // Neither the session attribute is set nor the repository methods are mocked and therefore return null Task task = TaskTestUtil.getValidTask(); - Mockito.when(repository.findOneWithTemplates(task.getId())).thenReturn(task); + User user = UserTestUtil.getUser(); - TaskShowDto dto = service.findById(task.getId()); + Mockito.when(repository.findOneWithTemplates(task.getId())).thenReturn(task); + TaskShowDto dto = service.findById(task.getId(), user); assertTaskEquals(task, dto); } + @Test + public void findByIdAccessGranted() throws Exception { + Task task = TaskTestUtil.getValidTask(); + Task newTask = TaskTestUtil.getValidTask(); + User user = UserTestUtil.getUser(); + Challenge challenge = ChallengeTestUtil.getChallenge(); + + Result result = new Result(); + result.setChallenge(challenge); + result.setUser(user); + + TaskResult taskResult = new TaskResult(); + taskResult.setSuccessful(true); + + TaskResultKey taskResultKey = new TaskResultKey(); + taskResultKey.setResult(result); + taskResultKey.setTask(task); + + ArrayList taskResultList = new ArrayList<>(); + taskResultList.add(taskResult); + result.setTaskResults(taskResultList); + + ArrayList tasks = new ArrayList<>(); + tasks.add(task); + tasks.add(newTask); + challenge.getChallengeTemplate().setTasks(tasks); + + Mockito.when(httpSession.getAttribute(ResultService.CURRENT_CHALLENGE)).thenReturn(challenge.getId()); + Mockito.when(userRepository.findOne(user.getId())).thenReturn(user); + Mockito.when(repository.findOneWithTemplates(task.getId())).thenReturn(task); + Mockito.when(repository.findOneWithTemplates(newTask.getId())).thenReturn(newTask); + Mockito.when(challengeRepository.findOne(challenge.getId())).thenReturn(challenge); + Mockito.when(resultRepository.findOneByUserAndChallenge(user.getId(), challenge.getId())).thenReturn(result); + + TaskShowDto dto = service.findById(newTask.getId(), user); + assertTaskEquals(newTask, dto); + } + @Test public void findAll() throws Exception { Task task = TaskTestUtil.getValidTask(); diff --git a/platform-server-rest/src/main/java/uno/cod/platform/server/rest/controller/TaskController.java b/platform-server-rest/src/main/java/uno/cod/platform/server/rest/controller/TaskController.java index d3ed9516..c01e2d0f 100644 --- a/platform-server-rest/src/main/java/uno/cod/platform/server/rest/controller/TaskController.java +++ b/platform-server-rest/src/main/java/uno/cod/platform/server/rest/controller/TaskController.java @@ -4,7 +4,9 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; +import uno.cod.platform.server.core.domain.User; import uno.cod.platform.server.core.dto.task.TaskCreateDto; import uno.cod.platform.server.core.dto.task.TaskShowDto; import uno.cod.platform.server.core.security.AllowedForAdmin; @@ -32,8 +34,8 @@ public ResponseEntity create(@Valid @RequestBody TaskCreateDto dto) { @RequestMapping(value = RestUrls.TASKS_ID, method = RequestMethod.GET) @PreAuthorize("isAuthenticated() and @securityService.canAccessTask(principal, #id)") - public ResponseEntity findById(@PathVariable UUID id) { - return new ResponseEntity<>(taskService.findById(id), HttpStatus.OK); + public ResponseEntity findById(@PathVariable UUID id, @AuthenticationPrincipal User user) { + return new ResponseEntity<>(taskService.findById(id, user), HttpStatus.OK); } @RequestMapping(value = RestUrls.TASKS, method = RequestMethod.GET, params = {"organization"})