From 6f42fe0ee62a7edb0c1ddec8e97f8642f6d3aeb9 Mon Sep 17 00:00:00 2001 From: Anton Dzyk Date: Wed, 24 Dec 2025 13:39:39 +0300 Subject: [PATCH] =?UTF-8?q?=D1=80=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ru/oa2/lti/ApplicationService.java | 68 ------------- .../{ => application}/config/AppConfig.java | 2 +- .../config/AppProperties.java | 2 +- .../controller/LaunchController.java | 62 +++--------- .../controller/TaskController.java | 80 +++++++++++++++ .../application/domain/carecase/GetTask.java | 5 + .../infrastructure/lms/LMSService.java | 9 ++ .../infrastructure/lms/LMSServiceImpl.java | 99 +++++++++++++++++++ .../repository/LMSContentRepository.java | 4 +- .../repository/TaskQueueRepository.java | 4 +- .../repository/entities/LMSContent.java | 3 +- .../repository/entities/Task.java | 6 +- .../repository/entities/TaskQueue.java | 5 +- .../infrastructure/runner/Runner.java | 2 +- .../infrastructure/runner/RunnerImpl.java | 2 +- .../service/jwt/JwtAssertionGenerator.java | 4 +- .../application/service/jwt/JwtService.java | 11 +++ .../service/jwt/JwtServiceImpl.java | 3 +- .../service/results/ResultService.java | 6 ++ .../service/results/ResultServiceImpl.java | 40 ++++---- .../application/service/task/TaskService.java | 24 +++++ .../service/task/TaskServiceImpl.java | 76 ++++++++++++++ .../oa2/lti/{ => application}/utils/Keys.java | 2 +- .../oa2/lti/controller/ResultController.java | 62 ------------ .../ru/oa2/lti/domain/carecase/GetTask.java | 5 - .../oa2/lti/domain/model/ResultRequest.java | 8 ++ .../model/auth}/IdTokenPayload.java | 2 +- .../model/auth}/LaunchPresentation.java | 2 +- .../model/auth}/LtiLogin.java | 2 +- .../model/auth}/NamesRoleService.java | 2 +- .../jwt => domain/model/auth}/Payload.java | 2 +- .../model/auth}/ResourceLink.java | 2 +- .../jwt => domain/model/auth}/Scope.java | 2 +- .../model/auth}/TokenContext.java | 2 +- .../model/auth}/TokenEndpoint.java | 2 +- .../model/results}/GradingType.java | 2 +- .../model/results}/Lineitems.java | 2 +- .../model/results}/ProgressType.java | 2 +- .../model/results}/ResultRequest.java | 2 +- .../model/results}/ResultResponse.java | 2 +- .../model/task}/TaskData.java | 2 +- .../model/task}/TaskQueueStatus.java | 2 +- .../model/task}/TaskResult.java | 2 +- .../model/task}/TaskType.java | 2 +- .../ru/oa2/lti/infrastructure/LMSService.java | 6 -- .../lti/infrastructure/LMSServiceImpl.java | 40 -------- .../java/ru/oa2/lti/model/ResultRequest.java | 8 -- src/main/java/ru/oa2/lti/model/User.java | 7 -- .../ru/oa2/lti/service/jwt/JwtService.java | 8 -- .../ru/oa2/lti/service/jwt/TokenService.java | 66 ------------- .../lti/service/results/ResultService.java | 10 -- .../ru/oa2/lti/service/task/TaskService.java | 27 ----- .../oa2/lti/service/task/TaskServiceImpl.java | 26 ----- src/main/resources/static/tool/lti/js/main.js | 3 +- src/test/java/ru/oa2/lti/ScopeTest.java | 2 +- .../ru/oa2/lti/infrastructure/RunnerTest.java | 4 +- src/test/java/ru/oa2/lti/jwt/IdTokenTest.java | 6 +- 57 files changed, 395 insertions(+), 448 deletions(-) delete mode 100644 src/main/java/ru/oa2/lti/ApplicationService.java rename src/main/java/ru/oa2/lti/{ => application}/config/AppConfig.java (97%) rename src/main/java/ru/oa2/lti/{ => application}/config/AppProperties.java (81%) rename src/main/java/ru/oa2/lti/{ => application}/controller/LaunchController.java (64%) create mode 100644 src/main/java/ru/oa2/lti/application/controller/TaskController.java create mode 100644 src/main/java/ru/oa2/lti/application/domain/carecase/GetTask.java create mode 100644 src/main/java/ru/oa2/lti/application/infrastructure/lms/LMSService.java create mode 100644 src/main/java/ru/oa2/lti/application/infrastructure/lms/LMSServiceImpl.java rename src/main/java/ru/oa2/lti/{ => application/infrastructure}/repository/LMSContentRepository.java (70%) rename src/main/java/ru/oa2/lti/{ => application/infrastructure}/repository/TaskQueueRepository.java (60%) rename src/main/java/ru/oa2/lti/{ => application/infrastructure}/repository/entities/LMSContent.java (88%) rename src/main/java/ru/oa2/lti/{ => application/infrastructure}/repository/entities/Task.java (75%) rename src/main/java/ru/oa2/lti/{ => application/infrastructure}/repository/entities/TaskQueue.java (80%) rename src/main/java/ru/oa2/lti/{ => application}/infrastructure/runner/Runner.java (73%) rename src/main/java/ru/oa2/lti/{ => application}/infrastructure/runner/RunnerImpl.java (97%) rename src/main/java/ru/oa2/lti/{ => application}/service/jwt/JwtAssertionGenerator.java (95%) create mode 100644 src/main/java/ru/oa2/lti/application/service/jwt/JwtService.java rename src/main/java/ru/oa2/lti/{ => application}/service/jwt/JwtServiceImpl.java (98%) create mode 100644 src/main/java/ru/oa2/lti/application/service/results/ResultService.java rename src/main/java/ru/oa2/lti/{ => application}/service/results/ResultServiceImpl.java (51%) create mode 100644 src/main/java/ru/oa2/lti/application/service/task/TaskService.java create mode 100644 src/main/java/ru/oa2/lti/application/service/task/TaskServiceImpl.java rename src/main/java/ru/oa2/lti/{ => application}/utils/Keys.java (86%) delete mode 100644 src/main/java/ru/oa2/lti/controller/ResultController.java delete mode 100644 src/main/java/ru/oa2/lti/domain/carecase/GetTask.java create mode 100644 src/main/java/ru/oa2/lti/domain/model/ResultRequest.java rename src/main/java/ru/oa2/lti/{service/jwt => domain/model/auth}/IdTokenPayload.java (93%) rename src/main/java/ru/oa2/lti/{service/jwt => domain/model/auth}/LaunchPresentation.java (83%) rename src/main/java/ru/oa2/lti/{model => domain/model/auth}/LtiLogin.java (85%) rename src/main/java/ru/oa2/lti/{service/jwt => domain/model/auth}/NamesRoleService.java (90%) rename src/main/java/ru/oa2/lti/{service/jwt => domain/model/auth}/Payload.java (90%) rename src/main/java/ru/oa2/lti/{service/jwt => domain/model/auth}/ResourceLink.java (71%) rename src/main/java/ru/oa2/lti/{service/jwt => domain/model/auth}/Scope.java (93%) rename src/main/java/ru/oa2/lti/{service/jwt => domain/model/auth}/TokenContext.java (81%) rename src/main/java/ru/oa2/lti/{service/jwt => domain/model/auth}/TokenEndpoint.java (95%) rename src/main/java/ru/oa2/lti/{service/results/dto => domain/model/results}/GradingType.java (71%) rename src/main/java/ru/oa2/lti/{service/results/dto => domain/model/results}/Lineitems.java (70%) rename src/main/java/ru/oa2/lti/{service/results/dto => domain/model/results}/ProgressType.java (68%) rename src/main/java/ru/oa2/lti/{service/results/dto => domain/model/results}/ResultRequest.java (88%) rename src/main/java/ru/oa2/lti/{service/results/dto => domain/model/results}/ResultResponse.java (59%) rename src/main/java/ru/oa2/lti/{model => domain/model/task}/TaskData.java (77%) rename src/main/java/ru/oa2/lti/{model => domain/model/task}/TaskQueueStatus.java (67%) rename src/main/java/ru/oa2/lti/{model => domain/model/task}/TaskResult.java (76%) rename src/main/java/ru/oa2/lti/{model => domain/model/task}/TaskType.java (58%) delete mode 100644 src/main/java/ru/oa2/lti/infrastructure/LMSService.java delete mode 100644 src/main/java/ru/oa2/lti/infrastructure/LMSServiceImpl.java delete mode 100644 src/main/java/ru/oa2/lti/model/ResultRequest.java delete mode 100644 src/main/java/ru/oa2/lti/model/User.java delete mode 100644 src/main/java/ru/oa2/lti/service/jwt/JwtService.java delete mode 100644 src/main/java/ru/oa2/lti/service/jwt/TokenService.java delete mode 100644 src/main/java/ru/oa2/lti/service/results/ResultService.java delete mode 100644 src/main/java/ru/oa2/lti/service/task/TaskService.java delete mode 100644 src/main/java/ru/oa2/lti/service/task/TaskServiceImpl.java diff --git a/src/main/java/ru/oa2/lti/ApplicationService.java b/src/main/java/ru/oa2/lti/ApplicationService.java deleted file mode 100644 index 8e3539f..0000000 --- a/src/main/java/ru/oa2/lti/ApplicationService.java +++ /dev/null @@ -1,68 +0,0 @@ -package ru.oa2.lti; - -import jakarta.transaction.Transactional; -import org.springframework.stereotype.Service; -import ru.oa2.lti.infrastructure.runner.Runner; -import ru.oa2.lti.model.LtiLogin; -import ru.oa2.lti.model.TaskData; -import ru.oa2.lti.repository.LMSContentRepository; -import ru.oa2.lti.repository.entities.LMSContent; -import ru.oa2.lti.repository.entities.Task; -import ru.oa2.lti.service.jwt.JwtService; -import ru.oa2.lti.service.jwt.Payload; -import ru.oa2.lti.service.results.dto.ResultResponse; - -import java.util.Collection; -import java.util.UUID; - -@Service -@Transactional -public class ApplicationService { - - private final JwtService jwtService; - private final LMSContentRepository lmsContentRepository; - private final Runner runner; - - public ApplicationService(JwtService jwtService, - LMSContentRepository lmsContentRepository, - Runner runner) { - this.jwtService = jwtService; - this.lmsContentRepository = lmsContentRepository; - this.runner = runner; - } - - public Payload getPayload(LtiLogin ltiLogin) { - return jwtService.getPayload(ltiLogin.getLoginHint()); - } - - public String getTask(UUID contextId) { - - var content = lmsContentRepository.getLMSContentByContentId(contextId); - - if(content.isPresent()) { - LMSContent lmsContent = content.get(); - Collection tasks = lmsContent.getTasks(); - - //TODO добавить версию в Task и выбирать самую старшую и опубликованную - TaskData data = tasks.stream().findFirst().get().getData(); - - if (!runner.run(contextId, data.getInitScript())) { - return "Init script FAILED"; - } - - return data.getDescription(); - } else { - return "Not Page"; - } - } - - public ResultResponse updateTask(String body) { - return new ResultResponse("success"); - } - - public ResultResponse saveResult(String body) { - - //TODO заполнять из результатов проверок check скрипта - return new ResultResponse("success"); - } -} diff --git a/src/main/java/ru/oa2/lti/config/AppConfig.java b/src/main/java/ru/oa2/lti/application/config/AppConfig.java similarity index 97% rename from src/main/java/ru/oa2/lti/config/AppConfig.java rename to src/main/java/ru/oa2/lti/application/config/AppConfig.java index 46ba29d..7aa443f 100644 --- a/src/main/java/ru/oa2/lti/config/AppConfig.java +++ b/src/main/java/ru/oa2/lti/application/config/AppConfig.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.config; +package ru.oa2.lti.application.config; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; diff --git a/src/main/java/ru/oa2/lti/config/AppProperties.java b/src/main/java/ru/oa2/lti/application/config/AppProperties.java similarity index 81% rename from src/main/java/ru/oa2/lti/config/AppProperties.java rename to src/main/java/ru/oa2/lti/application/config/AppProperties.java index 8379364..1f16284 100644 --- a/src/main/java/ru/oa2/lti/config/AppProperties.java +++ b/src/main/java/ru/oa2/lti/application/config/AppProperties.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.config; +package ru.oa2.lti.application.config; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/src/main/java/ru/oa2/lti/controller/LaunchController.java b/src/main/java/ru/oa2/lti/application/controller/LaunchController.java similarity index 64% rename from src/main/java/ru/oa2/lti/controller/LaunchController.java rename to src/main/java/ru/oa2/lti/application/controller/LaunchController.java index ceb3af5..14384ae 100644 --- a/src/main/java/ru/oa2/lti/controller/LaunchController.java +++ b/src/main/java/ru/oa2/lti/application/controller/LaunchController.java @@ -1,30 +1,30 @@ -package ru.oa2.lti.controller; +package ru.oa2.lti.application.controller; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpSession; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; -import ru.oa2.lti.ApplicationService; -import ru.oa2.lti.infrastructure.LMSService; -import ru.oa2.lti.model.LtiLogin; -import ru.oa2.lti.service.jwt.Payload; +import ru.oa2.lti.application.infrastructure.lms.LMSService; +import ru.oa2.lti.application.service.jwt.JwtService; +import ru.oa2.lti.domain.model.auth.LtiLogin; -import java.util.Objects; -@Slf4j +/* +Входная точка в external tool по протоколу LTI 1.3 + +#TODO расписать процесс и добавить линк на доку + */ @Controller @RequestMapping("/tool/lti") public class LaunchController { - private final ApplicationService service; + private final JwtService jwtService; private final LMSService lmsService; - public LaunchController(ApplicationService applicationService, + public LaunchController(JwtService jwtService, LMSService lmsService) { - this.service = applicationService; + this.jwtService = jwtService; this.lmsService = lmsService; } @@ -47,9 +47,7 @@ public class LaunchController { .targetLinkUri(targetLinkUri) .build(); - log.info("BODY: {}", ltiLogin); - - var payload = service.getPayload(ltiLogin); + var payload = jwtService.getPayload(ltiLogin.getLoginHint()); // 4. Сохранить access token в сессии HttpSession session = request.getSession(); @@ -66,37 +64,9 @@ public class LaunchController { return "redirect:/tool/lti/select"; } - @PostMapping("/task") - public ResponseEntity updateTask() { - - return service.updateTask("TODO"); - } - - @GetMapping("/task") - public String showDockerTas(Model model, - HttpServletRequest request) { - - var session = request.getSession(); - var payload = (Payload) session.getAttribute("payload"); - - if (payload != null) { - var data = service.getTask(payload.getContextId()); - - if (data == null) { - return "redirect:/error"; - } - - model.addAttribute("description", data); - } - - if (Objects.requireNonNull(payload).getCoach()) { - return "task-editor"; - } - return "task"; - } - @GetMapping("/select") public String select(Model model) { + //TODO доработать форму выбора существующих заданий return "select"; } @@ -105,10 +75,6 @@ public class LaunchController { @RequestParam("state") String state, HttpServletRequest request) { - if (log.isDebugEnabled()) { - log.debug("/redirect idToken: {}, state: {}", idToken, state); - } - HttpSession session = request.getSession(); session.setAttribute("id_token", idToken); session.setAttribute("state", state); diff --git a/src/main/java/ru/oa2/lti/application/controller/TaskController.java b/src/main/java/ru/oa2/lti/application/controller/TaskController.java new file mode 100644 index 0000000..0d58e5f --- /dev/null +++ b/src/main/java/ru/oa2/lti/application/controller/TaskController.java @@ -0,0 +1,80 @@ +package ru.oa2.lti.application.controller; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpSession; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import ru.oa2.lti.domain.model.auth.Payload; +import ru.oa2.lti.application.service.task.TaskService; +import ru.oa2.lti.domain.model.auth.LtiLogin; +import ru.oa2.lti.domain.model.ResultRequest; + +import java.util.Objects; + +/* +Контроллер работы с задачами(лабораторными работами) + +GET - возвращает контекст лабораторной работы +POST - обновление/создание лабораторной работы (только для преподавателей/администраторов) +POST /submit - отправка на автоматическую проверку + + */ +@Controller +@RequestMapping("/tool/lti/task") +public class TaskController { + + private final TaskService taskService; + + public TaskController(TaskService taskService) { + this.taskService = taskService; + } + + @GetMapping + public String showDockerTas(Model model, + HttpServletRequest request) { + + var session = request.getSession(); + var payload = (Payload) session.getAttribute("payload"); + + if (payload != null) { + var data = taskService.getTask(payload.getContextId()); + + if (data == null) { + return "redirect:/error"; + } + + model.addAttribute("description", data); + } + + if (Objects.requireNonNull(payload).getCoach()) { + return "task-editor"; + } + return "task"; + } + + @PostMapping + public ResponseEntity updateTask() { + + //TODO exception + taskService.saveTask("TODO", "TODO", "TODO"); + return ResponseEntity.accepted().build(); + } + + @PostMapping("/submit") + public ResponseEntity result(HttpServletRequest req) { + + HttpSession session = req.getSession(false); + if (session == null) return ResponseEntity.status(401).build(); + + var ltiLogin = (LtiLogin) session.getAttribute("lti_login"); + var idToken = (String) session.getAttribute("id_token"); + + return ResponseEntity + .accepted() + .body(taskService.checkTask(new ResultRequest(ltiLogin.getClientId(), idToken))); + } +} diff --git a/src/main/java/ru/oa2/lti/application/domain/carecase/GetTask.java b/src/main/java/ru/oa2/lti/application/domain/carecase/GetTask.java new file mode 100644 index 0000000..fcf909e --- /dev/null +++ b/src/main/java/ru/oa2/lti/application/domain/carecase/GetTask.java @@ -0,0 +1,5 @@ +package ru.oa2.lti.application.domain.carecase; + +public class GetTask { + +} diff --git a/src/main/java/ru/oa2/lti/application/infrastructure/lms/LMSService.java b/src/main/java/ru/oa2/lti/application/infrastructure/lms/LMSService.java new file mode 100644 index 0000000..cbfb68b --- /dev/null +++ b/src/main/java/ru/oa2/lti/application/infrastructure/lms/LMSService.java @@ -0,0 +1,9 @@ +package ru.oa2.lti.application.infrastructure.lms; + +public interface LMSService { + + String ltiAuth(String ltiLoginHint, String iss, String loginHint); + + // Вызывается после LTI-запуска + String exchangeForAccessToken(String clientId); +} diff --git a/src/main/java/ru/oa2/lti/application/infrastructure/lms/LMSServiceImpl.java b/src/main/java/ru/oa2/lti/application/infrastructure/lms/LMSServiceImpl.java new file mode 100644 index 0000000..c7e2452 --- /dev/null +++ b/src/main/java/ru/oa2/lti/application/infrastructure/lms/LMSServiceImpl.java @@ -0,0 +1,99 @@ +package ru.oa2.lti.application.infrastructure.lms; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestClient; +import ru.oa2.lti.application.config.AppProperties; +import ru.oa2.lti.application.service.jwt.JwtAssertionGenerator; +import ru.oa2.lti.domain.model.auth.Scope; + +import java.util.LinkedHashMap; +import java.util.Map; + +@Slf4j +@Component +public class LMSServiceImpl implements LMSService { + + private final RestClient restClient; + private final AppProperties appProperties; + + public LMSServiceImpl(RestClient restClient, AppProperties appProperties) { + this.restClient = restClient; + this.appProperties = appProperties; + } + + @Override + public String ltiAuth(String ltiLoginHint, String iss, String loginHint) { + var result = restClient + .get() + .uri("/lti/auth?" + + "state=start" + //TODO а какие могут быть статусы? нужно в Enum перенести + "&code=code1" + //TODO что за коды? + "&iss=" + iss + + "&login_hint=" + loginHint + + "&redirect_uri=" + appProperties.lmsUrl() + "/tool/lti/redirect" + + "<i_message_hint=" + ltiLoginHint) + .retrieve(); + + var body = result.toEntity(String.class).getBody(); + if (log.isDebugEnabled()) { + log.debug("lti/auth RESPONSE: {}", body); + } + return body; + } + + @Override + public String exchangeForAccessToken(String clientId) { + + var endpointUrl = appProperties.lmsUrl() + "/lti/token"; + + try { + + var clientAssertion = getClientAssertion(clientId, endpointUrl); + var body = getBody(clientAssertion); + + try { + var responseBody = restClient.post() + .uri(endpointUrl) + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .body(body) + .retrieve() + .body(Map.class); + + if (responseBody != null && responseBody.containsKey("access_token")) { + return (String) responseBody.get("access_token"); + } else { + throw new RuntimeException("Ответ не содержит access_token"); + } + + } catch (Exception e) { + throw new RuntimeException("Ошибка получения токена: " + e.getMessage(), e); + } + } catch (Exception e) { + throw new RuntimeException("Не удалось получить access token", e); + } + } + + private String getClientAssertion(String clientId, String endpointUrl) throws Exception { + // Генерируем client_assertion + return JwtAssertionGenerator.generateClientAssertion( + clientId, + endpointUrl, + "my-key-id-1" //TODO должен совпадать с тем, что в JWKS + ); + } + + private MultiValueMap getBody(String clientAssertion) { + + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("grant_type", "client_credentials"); + body.add("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"); + body.add("client_assertion", clientAssertion); + body.add("scope", Scope.scope(Scope.LINE_ITEM, Scope.SCOPE, Scope.ENDPOINT)); + + return body; + } +} diff --git a/src/main/java/ru/oa2/lti/repository/LMSContentRepository.java b/src/main/java/ru/oa2/lti/application/infrastructure/repository/LMSContentRepository.java similarity index 70% rename from src/main/java/ru/oa2/lti/repository/LMSContentRepository.java rename to src/main/java/ru/oa2/lti/application/infrastructure/repository/LMSContentRepository.java index c7c47c2..c309277 100644 --- a/src/main/java/ru/oa2/lti/repository/LMSContentRepository.java +++ b/src/main/java/ru/oa2/lti/application/infrastructure/repository/LMSContentRepository.java @@ -1,8 +1,8 @@ -package ru.oa2.lti.repository; +package ru.oa2.lti.application.infrastructure.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import ru.oa2.lti.repository.entities.LMSContent; +import ru.oa2.lti.application.infrastructure.repository.entities.LMSContent; import java.util.Optional; import java.util.UUID; diff --git a/src/main/java/ru/oa2/lti/repository/TaskQueueRepository.java b/src/main/java/ru/oa2/lti/application/infrastructure/repository/TaskQueueRepository.java similarity index 60% rename from src/main/java/ru/oa2/lti/repository/TaskQueueRepository.java rename to src/main/java/ru/oa2/lti/application/infrastructure/repository/TaskQueueRepository.java index f1c4802..2b9b572 100644 --- a/src/main/java/ru/oa2/lti/repository/TaskQueueRepository.java +++ b/src/main/java/ru/oa2/lti/application/infrastructure/repository/TaskQueueRepository.java @@ -1,8 +1,8 @@ -package ru.oa2.lti.repository; +package ru.oa2.lti.application.infrastructure.repository; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import ru.oa2.lti.repository.entities.TaskQueue; +import ru.oa2.lti.application.infrastructure.repository.entities.TaskQueue; @Repository public interface TaskQueueRepository extends JpaRepository { diff --git a/src/main/java/ru/oa2/lti/repository/entities/LMSContent.java b/src/main/java/ru/oa2/lti/application/infrastructure/repository/entities/LMSContent.java similarity index 88% rename from src/main/java/ru/oa2/lti/repository/entities/LMSContent.java rename to src/main/java/ru/oa2/lti/application/infrastructure/repository/entities/LMSContent.java index 678166b..cd3b7bb 100644 --- a/src/main/java/ru/oa2/lti/repository/entities/LMSContent.java +++ b/src/main/java/ru/oa2/lti/application/infrastructure/repository/entities/LMSContent.java @@ -1,7 +1,6 @@ -package ru.oa2.lti.repository.entities; +package ru.oa2.lti.application.infrastructure.repository.entities; import jakarta.persistence.*; -import lombok.Data; import lombok.Getter; import java.util.Collection; diff --git a/src/main/java/ru/oa2/lti/repository/entities/Task.java b/src/main/java/ru/oa2/lti/application/infrastructure/repository/entities/Task.java similarity index 75% rename from src/main/java/ru/oa2/lti/repository/entities/Task.java rename to src/main/java/ru/oa2/lti/application/infrastructure/repository/entities/Task.java index 92d9823..6374471 100644 --- a/src/main/java/ru/oa2/lti/repository/entities/Task.java +++ b/src/main/java/ru/oa2/lti/application/infrastructure/repository/entities/Task.java @@ -1,11 +1,11 @@ -package ru.oa2.lti.repository.entities; +package ru.oa2.lti.application.infrastructure.repository.entities; import jakarta.persistence.*; import lombok.Getter; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.type.SqlTypes; -import ru.oa2.lti.model.TaskData; -import ru.oa2.lti.model.TaskType; +import ru.oa2.lti.domain.model.task.TaskData; +import ru.oa2.lti.domain.model.task.TaskType; @Getter @Entity diff --git a/src/main/java/ru/oa2/lti/repository/entities/TaskQueue.java b/src/main/java/ru/oa2/lti/application/infrastructure/repository/entities/TaskQueue.java similarity index 80% rename from src/main/java/ru/oa2/lti/repository/entities/TaskQueue.java rename to src/main/java/ru/oa2/lti/application/infrastructure/repository/entities/TaskQueue.java index 4123174..ceaac58 100644 --- a/src/main/java/ru/oa2/lti/repository/entities/TaskQueue.java +++ b/src/main/java/ru/oa2/lti/application/infrastructure/repository/entities/TaskQueue.java @@ -1,9 +1,8 @@ -package ru.oa2.lti.repository.entities; +package ru.oa2.lti.application.infrastructure.repository.entities; import jakarta.persistence.*; -import lombok.Data; import lombok.Getter; -import ru.oa2.lti.model.TaskQueueStatus; +import ru.oa2.lti.domain.model.task.TaskQueueStatus; @Getter @Entity diff --git a/src/main/java/ru/oa2/lti/infrastructure/runner/Runner.java b/src/main/java/ru/oa2/lti/application/infrastructure/runner/Runner.java similarity index 73% rename from src/main/java/ru/oa2/lti/infrastructure/runner/Runner.java rename to src/main/java/ru/oa2/lti/application/infrastructure/runner/Runner.java index 3d9e2e5..9983e37 100644 --- a/src/main/java/ru/oa2/lti/infrastructure/runner/Runner.java +++ b/src/main/java/ru/oa2/lti/application/infrastructure/runner/Runner.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.infrastructure.runner; +package ru.oa2.lti.application.infrastructure.runner; import java.util.UUID; diff --git a/src/main/java/ru/oa2/lti/infrastructure/runner/RunnerImpl.java b/src/main/java/ru/oa2/lti/application/infrastructure/runner/RunnerImpl.java similarity index 97% rename from src/main/java/ru/oa2/lti/infrastructure/runner/RunnerImpl.java rename to src/main/java/ru/oa2/lti/application/infrastructure/runner/RunnerImpl.java index 116d92c..0609b08 100644 --- a/src/main/java/ru/oa2/lti/infrastructure/runner/RunnerImpl.java +++ b/src/main/java/ru/oa2/lti/application/infrastructure/runner/RunnerImpl.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.infrastructure.runner; +package ru.oa2.lti.application.infrastructure.runner; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/src/main/java/ru/oa2/lti/service/jwt/JwtAssertionGenerator.java b/src/main/java/ru/oa2/lti/application/service/jwt/JwtAssertionGenerator.java similarity index 95% rename from src/main/java/ru/oa2/lti/service/jwt/JwtAssertionGenerator.java rename to src/main/java/ru/oa2/lti/application/service/jwt/JwtAssertionGenerator.java index e5d388e..4fd0c55 100644 --- a/src/main/java/ru/oa2/lti/service/jwt/JwtAssertionGenerator.java +++ b/src/main/java/ru/oa2/lti/application/service/jwt/JwtAssertionGenerator.java @@ -1,11 +1,11 @@ -package ru.oa2.lti.service.jwt; +package ru.oa2.lti.application.service.jwt; import com.nimbusds.jose.JWSAlgorithm; import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.crypto.RSASSASigner; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; -import ru.oa2.lti.utils.Keys; +import ru.oa2.lti.application.utils.Keys; import java.security.KeyFactory; import java.security.interfaces.RSAPrivateKey; diff --git a/src/main/java/ru/oa2/lti/application/service/jwt/JwtService.java b/src/main/java/ru/oa2/lti/application/service/jwt/JwtService.java new file mode 100644 index 0000000..9d23a49 --- /dev/null +++ b/src/main/java/ru/oa2/lti/application/service/jwt/JwtService.java @@ -0,0 +1,11 @@ +package ru.oa2.lti.application.service.jwt; + +import ru.oa2.lti.domain.model.auth.IdTokenPayload; +import ru.oa2.lti.domain.model.auth.Payload; + +public interface JwtService { + + Payload getPayload(String jwt); + + IdTokenPayload getTokenPayload(String jwt); +} diff --git a/src/main/java/ru/oa2/lti/service/jwt/JwtServiceImpl.java b/src/main/java/ru/oa2/lti/application/service/jwt/JwtServiceImpl.java similarity index 98% rename from src/main/java/ru/oa2/lti/service/jwt/JwtServiceImpl.java rename to src/main/java/ru/oa2/lti/application/service/jwt/JwtServiceImpl.java index ba3a9c5..8584165 100644 --- a/src/main/java/ru/oa2/lti/service/jwt/JwtServiceImpl.java +++ b/src/main/java/ru/oa2/lti/application/service/jwt/JwtServiceImpl.java @@ -1,8 +1,9 @@ -package ru.oa2.lti.service.jwt; +package ru.oa2.lti.application.service.jwt; import com.nimbusds.jose.shaded.gson.internal.LinkedTreeMap; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.stereotype.Service; +import ru.oa2.lti.domain.model.auth.*; import java.time.Instant; import java.time.LocalDateTime; diff --git a/src/main/java/ru/oa2/lti/application/service/results/ResultService.java b/src/main/java/ru/oa2/lti/application/service/results/ResultService.java new file mode 100644 index 0000000..e948bfb --- /dev/null +++ b/src/main/java/ru/oa2/lti/application/service/results/ResultService.java @@ -0,0 +1,6 @@ +package ru.oa2.lti.application.service.results; + +public interface ResultService { + + void setResult(String accessToken, String idToken); +} diff --git a/src/main/java/ru/oa2/lti/service/results/ResultServiceImpl.java b/src/main/java/ru/oa2/lti/application/service/results/ResultServiceImpl.java similarity index 51% rename from src/main/java/ru/oa2/lti/service/results/ResultServiceImpl.java rename to src/main/java/ru/oa2/lti/application/service/results/ResultServiceImpl.java index 0c89298..6acb1f3 100644 --- a/src/main/java/ru/oa2/lti/service/results/ResultServiceImpl.java +++ b/src/main/java/ru/oa2/lti/application/service/results/ResultServiceImpl.java @@ -1,14 +1,13 @@ -package ru.oa2.lti.service.results; +package ru.oa2.lti.application.service.results; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClient; -import ru.oa2.lti.service.jwt.IdTokenPayload; -import ru.oa2.lti.service.results.dto.GradingType; -import ru.oa2.lti.service.results.dto.Lineitems; -import ru.oa2.lti.service.results.dto.ProgressType; -import ru.oa2.lti.service.results.dto.ResultRequest; +import ru.oa2.lti.application.service.jwt.JwtService; +import ru.oa2.lti.domain.model.results.GradingType; +import ru.oa2.lti.domain.model.results.ProgressType; +import ru.oa2.lti.domain.model.results.ResultRequest; import java.time.LocalDateTime; @@ -18,29 +17,26 @@ public class ResultServiceImpl implements ResultService { private final RestClient restClient; private final ObjectMapper mapper; + private final JwtService jwtService; + + private final String CONTENT_TYPE = "application/vnd.ims.lis.v1.score+json"; + private final String ACCEPT = "application/vnd.ims.lis.v1.score+json"; + + public ResultServiceImpl(RestClient client, + ObjectMapper mapper, + JwtService jwtService) { - public ResultServiceImpl(RestClient client, ObjectMapper mapper) { this.restClient = client; this.mapper = mapper; + this.jwtService = jwtService; } @Override - public void setResult(String accessToken, IdTokenPayload idToken) { + public void setResult(String accessToken, String idTokenString) { - // http://openolat.local/lti/ags/b0d12061-2564-47a0-9291-b0d226f1eefe/context/112999233990970/lineitems/112999233990979/lineitem + var idToken = jwtService.getTokenPayload(idTokenString); - - var resp = restClient.get() - .uri("http://openolat.local/lti/ags/b0d12061-2564-47a0-9291-b0d226f1eefe/context/112999233990970/lineitems/112999233990979/lineitem") - .header("Authorization", "Bearer " + accessToken) - .header("Content-Type", "application/vnd.ims.lis.v1.score+json") - .header("Accept", "application/vnd.ims.lis.v1.score+json") - .retrieve(); - - var respBody = resp.toEntity(String.class).getBody(); try { - Lineitems lineitems = mapper.readValue(respBody, Lineitems.class); - var body = mapper.writeValueAsString( ResultRequest.builder() .scoreGiven(1L) @@ -56,8 +52,8 @@ public class ResultServiceImpl implements ResultService { .post() .uri(idToken.getTokenEndpoint().lineitem() + "/scores/result") .header("Authorization", "Bearer " + accessToken) - .header("Content-Type", "application/vnd.ims.lis.v1.score+json") - .header("Accept", "application/vnd.ims.lis.v1.score+json") + .header("Content-Type", CONTENT_TYPE) + .header("Accept", ACCEPT) .body(body) .retrieve(); diff --git a/src/main/java/ru/oa2/lti/application/service/task/TaskService.java b/src/main/java/ru/oa2/lti/application/service/task/TaskService.java new file mode 100644 index 0000000..d4740df --- /dev/null +++ b/src/main/java/ru/oa2/lti/application/service/task/TaskService.java @@ -0,0 +1,24 @@ +package ru.oa2.lti.application.service.task; + +import ru.oa2.lti.domain.model.ResultRequest; +import ru.oa2.lti.domain.model.results.ResultResponse; + +import java.util.UUID; + +public interface TaskService { + + /* + Получение задачи (контекста лабораторной работы) + */ + String getTask(UUID contextId); + + /* + Запуск проверки через скрипт + */ + ResultResponse checkTask(ResultRequest resultRequest); + + /* + Сохранение/обновление task-а + */ + void saveTask(String initScript, String checkScript, String description); +} diff --git a/src/main/java/ru/oa2/lti/application/service/task/TaskServiceImpl.java b/src/main/java/ru/oa2/lti/application/service/task/TaskServiceImpl.java new file mode 100644 index 0000000..badd0a4 --- /dev/null +++ b/src/main/java/ru/oa2/lti/application/service/task/TaskServiceImpl.java @@ -0,0 +1,76 @@ +package ru.oa2.lti.application.service.task; + +import org.springframework.stereotype.Service; +import ru.oa2.lti.application.infrastructure.lms.LMSService; +import ru.oa2.lti.application.infrastructure.runner.Runner; +import ru.oa2.lti.application.service.results.ResultService; +import ru.oa2.lti.domain.model.ResultRequest; +import ru.oa2.lti.domain.model.task.TaskData; +import ru.oa2.lti.application.infrastructure.repository.LMSContentRepository; +import ru.oa2.lti.application.infrastructure.repository.entities.LMSContent; +import ru.oa2.lti.application.infrastructure.repository.entities.Task; +import ru.oa2.lti.domain.model.results.ResultResponse; + +import java.util.Collection; +import java.util.UUID; + +@Service +public class TaskServiceImpl implements TaskService { + + private final LMSContentRepository lmsContentRepository; + private final Runner runner; + + //TODO объединить в один? + final ResultService resultService; + final LMSService lmsService; + + public TaskServiceImpl(LMSContentRepository lmsContentRepository, + Runner runner, + ResultService resultService, + LMSService lmsService) { + + this.lmsContentRepository = lmsContentRepository; + this.runner = runner; + this.resultService = resultService; + this.lmsService = lmsService; + } + + @Override + public String getTask(UUID contextId) { + var content = lmsContentRepository.getLMSContentByContentId(contextId); + + if(content.isPresent()) { + LMSContent lmsContent = content.get(); + Collection tasks = lmsContent.getTasks(); + + //TODO добавить версию в Task и выбирать самую старшую и опубликованную + TaskData data = tasks.stream().findFirst().get().getData(); + + //TODO string -> exception? + if (!runner.run(contextId, data.getInitScript())) { + return "Init script FAILED"; + } + + return data.getDescription(); + } else { + return "Not Page"; + } + } + + @Override + public ResultResponse checkTask(ResultRequest resultRequest) { + + //TODO запуск скрипта проверки + var assessToken = lmsService.exchangeForAccessToken( + resultRequest.clientId()); + resultService.setResult(assessToken, resultRequest.idToken()); + + //TODO обработка и запуск скрипта + return new ResultResponse("success"); + } + + @Override + public void saveTask(String initScript, String checkScript, String description) { + //TODO + } +} diff --git a/src/main/java/ru/oa2/lti/utils/Keys.java b/src/main/java/ru/oa2/lti/application/utils/Keys.java similarity index 86% rename from src/main/java/ru/oa2/lti/utils/Keys.java rename to src/main/java/ru/oa2/lti/application/utils/Keys.java index a474372..9141058 100644 --- a/src/main/java/ru/oa2/lti/utils/Keys.java +++ b/src/main/java/ru/oa2/lti/application/utils/Keys.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.utils; +package ru.oa2.lti.application.utils; import java.io.IOException; import java.nio.file.Files; diff --git a/src/main/java/ru/oa2/lti/controller/ResultController.java b/src/main/java/ru/oa2/lti/controller/ResultController.java deleted file mode 100644 index 0be247a..0000000 --- a/src/main/java/ru/oa2/lti/controller/ResultController.java +++ /dev/null @@ -1,62 +0,0 @@ -package ru.oa2.lti.controller; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpSession; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import ru.oa2.lti.ApplicationService; -import ru.oa2.lti.model.LtiLogin; -import ru.oa2.lti.service.jwt.JwtService; -import ru.oa2.lti.service.jwt.TokenService; -import ru.oa2.lti.service.results.ResultService; - -@Slf4j -@RestController -@RequestMapping("/tool/lti/result") -public class ResultController { - - final ApplicationService service; - final ResultService resultService; - final TokenService tokenService; - final JwtService jwtService; - - public ResultController(ApplicationService applicationService, - ResultService resultService, - TokenService tokenService, - JwtService jwtService) { - this.service = applicationService; - this.resultService = resultService; - this.tokenService = tokenService; - this.jwtService = jwtService; - } - - @PostMapping("/docker") - public ResponseEntity result(@RequestBody String body, - HttpServletRequest req) { - - log.info("RESULT: {}", body); - - HttpSession session = req.getSession(false); - if (session == null) return ResponseEntity.status(401).build(); - - //TODO запуск скрипта проверки - var ltiLogin = (LtiLogin) session.getAttribute("lti_login"); - var assessToken = tokenService.exchangeForAccessToken( - ltiLogin.getClientId()); - - String idToken = (String) session.getAttribute("id_token"); - - resultService.setResult( - assessToken, - jwtService.getTokenPayload(idToken) - ); - - return ResponseEntity - .accepted() - .body(service.saveResult(body)); - } -} diff --git a/src/main/java/ru/oa2/lti/domain/carecase/GetTask.java b/src/main/java/ru/oa2/lti/domain/carecase/GetTask.java deleted file mode 100644 index 846d44f..0000000 --- a/src/main/java/ru/oa2/lti/domain/carecase/GetTask.java +++ /dev/null @@ -1,5 +0,0 @@ -package ru.oa2.lti.domain.carecase; - -public class GetTask { - -} diff --git a/src/main/java/ru/oa2/lti/domain/model/ResultRequest.java b/src/main/java/ru/oa2/lti/domain/model/ResultRequest.java new file mode 100644 index 0000000..78189cb --- /dev/null +++ b/src/main/java/ru/oa2/lti/domain/model/ResultRequest.java @@ -0,0 +1,8 @@ +package ru.oa2.lti.domain.model; + +//TODO 2 одинаковых имени? ) +public record ResultRequest( + String clientId, + String idToken +) { +} diff --git a/src/main/java/ru/oa2/lti/service/jwt/IdTokenPayload.java b/src/main/java/ru/oa2/lti/domain/model/auth/IdTokenPayload.java similarity index 93% rename from src/main/java/ru/oa2/lti/service/jwt/IdTokenPayload.java rename to src/main/java/ru/oa2/lti/domain/model/auth/IdTokenPayload.java index 598527c..d84fdb0 100644 --- a/src/main/java/ru/oa2/lti/service/jwt/IdTokenPayload.java +++ b/src/main/java/ru/oa2/lti/domain/model/auth/IdTokenPayload.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.jwt; +package ru.oa2.lti.domain.model.auth; import lombok.Data; diff --git a/src/main/java/ru/oa2/lti/service/jwt/LaunchPresentation.java b/src/main/java/ru/oa2/lti/domain/model/auth/LaunchPresentation.java similarity index 83% rename from src/main/java/ru/oa2/lti/service/jwt/LaunchPresentation.java rename to src/main/java/ru/oa2/lti/domain/model/auth/LaunchPresentation.java index cf75349..b603a91 100644 --- a/src/main/java/ru/oa2/lti/service/jwt/LaunchPresentation.java +++ b/src/main/java/ru/oa2/lti/domain/model/auth/LaunchPresentation.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.jwt; +package ru.oa2.lti.domain.model.auth; /* "https://purl.imsglobal.org/spec/lti/claim/launch_presentation" : { diff --git a/src/main/java/ru/oa2/lti/model/LtiLogin.java b/src/main/java/ru/oa2/lti/domain/model/auth/LtiLogin.java similarity index 85% rename from src/main/java/ru/oa2/lti/model/LtiLogin.java rename to src/main/java/ru/oa2/lti/domain/model/auth/LtiLogin.java index 2f44812..236f834 100644 --- a/src/main/java/ru/oa2/lti/model/LtiLogin.java +++ b/src/main/java/ru/oa2/lti/domain/model/auth/LtiLogin.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.model; +package ru.oa2.lti.domain.model.auth; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/ru/oa2/lti/service/jwt/NamesRoleService.java b/src/main/java/ru/oa2/lti/domain/model/auth/NamesRoleService.java similarity index 90% rename from src/main/java/ru/oa2/lti/service/jwt/NamesRoleService.java rename to src/main/java/ru/oa2/lti/domain/model/auth/NamesRoleService.java index 167fa3d..80995a0 100644 --- a/src/main/java/ru/oa2/lti/service/jwt/NamesRoleService.java +++ b/src/main/java/ru/oa2/lti/domain/model/auth/NamesRoleService.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.jwt; +package ru.oa2.lti.domain.model.auth; import java.util.List; diff --git a/src/main/java/ru/oa2/lti/service/jwt/Payload.java b/src/main/java/ru/oa2/lti/domain/model/auth/Payload.java similarity index 90% rename from src/main/java/ru/oa2/lti/service/jwt/Payload.java rename to src/main/java/ru/oa2/lti/domain/model/auth/Payload.java index f50840e..b3dc1ca 100644 --- a/src/main/java/ru/oa2/lti/service/jwt/Payload.java +++ b/src/main/java/ru/oa2/lti/domain/model/auth/Payload.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.jwt; +package ru.oa2.lti.domain.model.auth; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/src/main/java/ru/oa2/lti/service/jwt/ResourceLink.java b/src/main/java/ru/oa2/lti/domain/model/auth/ResourceLink.java similarity index 71% rename from src/main/java/ru/oa2/lti/service/jwt/ResourceLink.java rename to src/main/java/ru/oa2/lti/domain/model/auth/ResourceLink.java index 788372e..fb4e261 100644 --- a/src/main/java/ru/oa2/lti/service/jwt/ResourceLink.java +++ b/src/main/java/ru/oa2/lti/domain/model/auth/ResourceLink.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.jwt; +package ru.oa2.lti.domain.model.auth; import java.util.UUID; diff --git a/src/main/java/ru/oa2/lti/service/jwt/Scope.java b/src/main/java/ru/oa2/lti/domain/model/auth/Scope.java similarity index 93% rename from src/main/java/ru/oa2/lti/service/jwt/Scope.java rename to src/main/java/ru/oa2/lti/domain/model/auth/Scope.java index 3d9c728..edb800b 100644 --- a/src/main/java/ru/oa2/lti/service/jwt/Scope.java +++ b/src/main/java/ru/oa2/lti/domain/model/auth/Scope.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.jwt; +package ru.oa2.lti.domain.model.auth; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/ru/oa2/lti/service/jwt/TokenContext.java b/src/main/java/ru/oa2/lti/domain/model/auth/TokenContext.java similarity index 81% rename from src/main/java/ru/oa2/lti/service/jwt/TokenContext.java rename to src/main/java/ru/oa2/lti/domain/model/auth/TokenContext.java index 19d0431..8a89ccc 100644 --- a/src/main/java/ru/oa2/lti/service/jwt/TokenContext.java +++ b/src/main/java/ru/oa2/lti/domain/model/auth/TokenContext.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.jwt; +package ru.oa2.lti.domain.model.auth; import java.util.List; import java.util.UUID; diff --git a/src/main/java/ru/oa2/lti/service/jwt/TokenEndpoint.java b/src/main/java/ru/oa2/lti/domain/model/auth/TokenEndpoint.java similarity index 95% rename from src/main/java/ru/oa2/lti/service/jwt/TokenEndpoint.java rename to src/main/java/ru/oa2/lti/domain/model/auth/TokenEndpoint.java index 39c3788..f6013e8 100644 --- a/src/main/java/ru/oa2/lti/service/jwt/TokenEndpoint.java +++ b/src/main/java/ru/oa2/lti/domain/model/auth/TokenEndpoint.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.jwt; +package ru.oa2.lti.domain.model.auth; import java.util.List; diff --git a/src/main/java/ru/oa2/lti/service/results/dto/GradingType.java b/src/main/java/ru/oa2/lti/domain/model/results/GradingType.java similarity index 71% rename from src/main/java/ru/oa2/lti/service/results/dto/GradingType.java rename to src/main/java/ru/oa2/lti/domain/model/results/GradingType.java index be43d2a..b377893 100644 --- a/src/main/java/ru/oa2/lti/service/results/dto/GradingType.java +++ b/src/main/java/ru/oa2/lti/domain/model/results/GradingType.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.results.dto; +package ru.oa2.lti.domain.model.results; public enum GradingType { NotStarted, diff --git a/src/main/java/ru/oa2/lti/service/results/dto/Lineitems.java b/src/main/java/ru/oa2/lti/domain/model/results/Lineitems.java similarity index 70% rename from src/main/java/ru/oa2/lti/service/results/dto/Lineitems.java rename to src/main/java/ru/oa2/lti/domain/model/results/Lineitems.java index 6ca5e3b..ce31bc5 100644 --- a/src/main/java/ru/oa2/lti/service/results/dto/Lineitems.java +++ b/src/main/java/ru/oa2/lti/domain/model/results/Lineitems.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.results.dto; +package ru.oa2.lti.domain.model.results; public record Lineitems( String id, diff --git a/src/main/java/ru/oa2/lti/service/results/dto/ProgressType.java b/src/main/java/ru/oa2/lti/domain/model/results/ProgressType.java similarity index 68% rename from src/main/java/ru/oa2/lti/service/results/dto/ProgressType.java rename to src/main/java/ru/oa2/lti/domain/model/results/ProgressType.java index 331dda2..ac12d05 100644 --- a/src/main/java/ru/oa2/lti/service/results/dto/ProgressType.java +++ b/src/main/java/ru/oa2/lti/domain/model/results/ProgressType.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.results.dto; +package ru.oa2.lti.domain.model.results; public enum ProgressType { Initialized, diff --git a/src/main/java/ru/oa2/lti/service/results/dto/ResultRequest.java b/src/main/java/ru/oa2/lti/domain/model/results/ResultRequest.java similarity index 88% rename from src/main/java/ru/oa2/lti/service/results/dto/ResultRequest.java rename to src/main/java/ru/oa2/lti/domain/model/results/ResultRequest.java index 9e4d73e..aae8306 100644 --- a/src/main/java/ru/oa2/lti/service/results/dto/ResultRequest.java +++ b/src/main/java/ru/oa2/lti/domain/model/results/ResultRequest.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.results.dto; +package ru.oa2.lti.domain.model.results; import lombok.Builder; diff --git a/src/main/java/ru/oa2/lti/service/results/dto/ResultResponse.java b/src/main/java/ru/oa2/lti/domain/model/results/ResultResponse.java similarity index 59% rename from src/main/java/ru/oa2/lti/service/results/dto/ResultResponse.java rename to src/main/java/ru/oa2/lti/domain/model/results/ResultResponse.java index 631ec06..2eb4a05 100644 --- a/src/main/java/ru/oa2/lti/service/results/dto/ResultResponse.java +++ b/src/main/java/ru/oa2/lti/domain/model/results/ResultResponse.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.service.results.dto; +package ru.oa2.lti.domain.model.results; public record ResultResponse( String status diff --git a/src/main/java/ru/oa2/lti/model/TaskData.java b/src/main/java/ru/oa2/lti/domain/model/task/TaskData.java similarity index 77% rename from src/main/java/ru/oa2/lti/model/TaskData.java rename to src/main/java/ru/oa2/lti/domain/model/task/TaskData.java index 054b2ec..fc7f59d 100644 --- a/src/main/java/ru/oa2/lti/model/TaskData.java +++ b/src/main/java/ru/oa2/lti/domain/model/task/TaskData.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.model; +package ru.oa2.lti.domain.model.task; import lombok.Data; diff --git a/src/main/java/ru/oa2/lti/model/TaskQueueStatus.java b/src/main/java/ru/oa2/lti/domain/model/task/TaskQueueStatus.java similarity index 67% rename from src/main/java/ru/oa2/lti/model/TaskQueueStatus.java rename to src/main/java/ru/oa2/lti/domain/model/task/TaskQueueStatus.java index fbb1f24..e3690a3 100644 --- a/src/main/java/ru/oa2/lti/model/TaskQueueStatus.java +++ b/src/main/java/ru/oa2/lti/domain/model/task/TaskQueueStatus.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.model; +package ru.oa2.lti.domain.model.task; public enum TaskQueueStatus { NEW, diff --git a/src/main/java/ru/oa2/lti/model/TaskResult.java b/src/main/java/ru/oa2/lti/domain/model/task/TaskResult.java similarity index 76% rename from src/main/java/ru/oa2/lti/model/TaskResult.java rename to src/main/java/ru/oa2/lti/domain/model/task/TaskResult.java index a18d8b6..3ba3d9a 100644 --- a/src/main/java/ru/oa2/lti/model/TaskResult.java +++ b/src/main/java/ru/oa2/lti/domain/model/task/TaskResult.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.model; +package ru.oa2.lti.domain.model.task; public record TaskResult( //TODO результат работы(лог), true/false, error:, оценка diff --git a/src/main/java/ru/oa2/lti/model/TaskType.java b/src/main/java/ru/oa2/lti/domain/model/task/TaskType.java similarity index 58% rename from src/main/java/ru/oa2/lti/model/TaskType.java rename to src/main/java/ru/oa2/lti/domain/model/task/TaskType.java index f3e2b47..cbfed09 100644 --- a/src/main/java/ru/oa2/lti/model/TaskType.java +++ b/src/main/java/ru/oa2/lti/domain/model/task/TaskType.java @@ -1,4 +1,4 @@ -package ru.oa2.lti.model; +package ru.oa2.lti.domain.model.task; public enum TaskType { DOCKER, diff --git a/src/main/java/ru/oa2/lti/infrastructure/LMSService.java b/src/main/java/ru/oa2/lti/infrastructure/LMSService.java deleted file mode 100644 index b408dda..0000000 --- a/src/main/java/ru/oa2/lti/infrastructure/LMSService.java +++ /dev/null @@ -1,6 +0,0 @@ -package ru.oa2.lti.infrastructure; - -public interface LMSService { - - String ltiAuth(String ltiLoginHint, String iss, String loginHint); -} diff --git a/src/main/java/ru/oa2/lti/infrastructure/LMSServiceImpl.java b/src/main/java/ru/oa2/lti/infrastructure/LMSServiceImpl.java deleted file mode 100644 index bfe35f8..0000000 --- a/src/main/java/ru/oa2/lti/infrastructure/LMSServiceImpl.java +++ /dev/null @@ -1,40 +0,0 @@ -package ru.oa2.lti.infrastructure; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Component; -import org.springframework.web.client.RestClient; -import ru.oa2.lti.config.AppProperties; - -@Slf4j -@Component -public class LMSServiceImpl implements LMSService { - - private final RestClient restClient; - private final AppProperties appProperties; - - public LMSServiceImpl(RestClient restClient, AppProperties appProperties) { - this.restClient = restClient; - this.appProperties = appProperties; - } - - @Override - public String ltiAuth(String ltiLoginHint, String iss, String loginHint) { - var result = restClient - .get() - .uri("/lti/auth?" + - "state=start" + - "&code=code1" + - "&iss=" + iss + - "&login_hint=" + loginHint + - "&redirect_uri=" + appProperties.lmsUrl() + "/tool/lti/redirect" + - "<i_message_hint=" + ltiLoginHint) - .retrieve(); - - ResponseEntity body = result.toEntity(String.class); - if (log.isDebugEnabled()) { - log.debug("lti/auth RESPONSE: {}", body); - } - return body.getBody(); - } -} diff --git a/src/main/java/ru/oa2/lti/model/ResultRequest.java b/src/main/java/ru/oa2/lti/model/ResultRequest.java deleted file mode 100644 index d7a9b7b..0000000 --- a/src/main/java/ru/oa2/lti/model/ResultRequest.java +++ /dev/null @@ -1,8 +0,0 @@ -package ru.oa2.lti.model; - -public record ResultRequest( - String taskId, - String userId, - String answer -) { -} diff --git a/src/main/java/ru/oa2/lti/model/User.java b/src/main/java/ru/oa2/lti/model/User.java deleted file mode 100644 index d7b4e1a..0000000 --- a/src/main/java/ru/oa2/lti/model/User.java +++ /dev/null @@ -1,7 +0,0 @@ -package ru.oa2.lti.model; - -public record User( - String clientId, - String role -) { -} diff --git a/src/main/java/ru/oa2/lti/service/jwt/JwtService.java b/src/main/java/ru/oa2/lti/service/jwt/JwtService.java deleted file mode 100644 index 2ceae25..0000000 --- a/src/main/java/ru/oa2/lti/service/jwt/JwtService.java +++ /dev/null @@ -1,8 +0,0 @@ -package ru.oa2.lti.service.jwt; - -public interface JwtService { - - Payload getPayload(String jwt); - - IdTokenPayload getTokenPayload(String jwt); -} diff --git a/src/main/java/ru/oa2/lti/service/jwt/TokenService.java b/src/main/java/ru/oa2/lti/service/jwt/TokenService.java deleted file mode 100644 index f435282..0000000 --- a/src/main/java/ru/oa2/lti/service/jwt/TokenService.java +++ /dev/null @@ -1,66 +0,0 @@ -package ru.oa2.lti.service.jwt; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.*; -import org.springframework.stereotype.Service; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.client.RestClient; -import org.springframework.web.client.RestTemplate; -import ru.oa2.lti.config.AppProperties; - -import java.util.Map; - -@Slf4j -@Service -public class TokenService { - - private final RestTemplate restTemplate = new RestTemplate(); - private final AppProperties appProperties; - - public TokenService(AppProperties appProperties) { - this.appProperties = appProperties; - } - - // Вызывается после LTI-запуска - public String exchangeForAccessToken( - String clientId) { - - var endpointUrl = appProperties.lmsUrl() + "/lti/token"; - - try { - // Генерируем client_assertion - String clientAssertion = JwtAssertionGenerator.generateClientAssertion( - clientId, - endpointUrl, - "my-key-id-1" // должен совпадать с тем, что в JWKS - ); - - // Формируем тело запроса - MultiValueMap body = new LinkedMultiValueMap<>(); - body.add("grant_type", "client_credentials"); - body.add("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"); - body.add("client_assertion", clientAssertion); - body.add("scope", Scope.scope(Scope.LINE_ITEM, Scope.SCOPE, Scope.ENDPOINT)); - - // Заголовки - HttpHeaders headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); - - HttpEntity> request = new HttpEntity<>(body, headers); - - // Отправляем запрос к OpenOLAT - ResponseEntity response = restTemplate.postForEntity(endpointUrl, request, Map.class); - - if (response.getStatusCode() == HttpStatus.OK) { - Map responseBody = response.getBody(); - return (String) responseBody.get("access_token"); - } else { - throw new RuntimeException("Ошибка получения токена: " + response.getStatusCode()); - } - - } catch (Exception e) { - throw new RuntimeException("Не удалось получить access token", e); - } - } -} \ No newline at end of file diff --git a/src/main/java/ru/oa2/lti/service/results/ResultService.java b/src/main/java/ru/oa2/lti/service/results/ResultService.java deleted file mode 100644 index d37a840..0000000 --- a/src/main/java/ru/oa2/lti/service/results/ResultService.java +++ /dev/null @@ -1,10 +0,0 @@ -package ru.oa2.lti.service.results; - -import ru.oa2.lti.service.jwt.IdTokenPayload; - -import java.util.UUID; - -public interface ResultService { - - void setResult(String accessToken, IdTokenPayload idToken); -} diff --git a/src/main/java/ru/oa2/lti/service/task/TaskService.java b/src/main/java/ru/oa2/lti/service/task/TaskService.java deleted file mode 100644 index da0b909..0000000 --- a/src/main/java/ru/oa2/lti/service/task/TaskService.java +++ /dev/null @@ -1,27 +0,0 @@ -package ru.oa2.lti.service.task; - -import ru.oa2.lti.model.ResultRequest; -import ru.oa2.lti.model.TaskResult; -import ru.oa2.lti.model.User; - -import java.util.UUID; - -public interface TaskService { - - /* - Получение задачи (контекста лабораторной работы) - */ - //TODO возвращаем объект -> в String отдельный тех.класс сериализации через шаблонизатор - String getTask(String id, User user); - - /* - Отправить ответ по задаче - UUID - id - kеу kafka message? - */ - UUID submit(ResultRequest resultRequest); - - /* - Проверить результат по UUID отправленного результата - */ - TaskResult getResult(UUID requestId); -} diff --git a/src/main/java/ru/oa2/lti/service/task/TaskServiceImpl.java b/src/main/java/ru/oa2/lti/service/task/TaskServiceImpl.java deleted file mode 100644 index c36db20..0000000 --- a/src/main/java/ru/oa2/lti/service/task/TaskServiceImpl.java +++ /dev/null @@ -1,26 +0,0 @@ -package ru.oa2.lti.service.task; - -import ru.oa2.lti.model.ResultRequest; -import ru.oa2.lti.model.TaskResult; -import ru.oa2.lti.model.User; - -import java.util.UUID; - -//TODO реализовать методы -public class TaskServiceImpl implements TaskService { - - @Override - public String getTask(String id, User user) { - return ""; - } - - @Override - public UUID submit(ResultRequest resultRequest) { - return null; - } - - @Override - public TaskResult getResult(UUID requestId) { - return null; - } -} diff --git a/src/main/resources/static/tool/lti/js/main.js b/src/main/resources/static/tool/lti/js/main.js index cd2a429..0d551bc 100644 --- a/src/main/resources/static/tool/lti/js/main.js +++ b/src/main/resources/static/tool/lti/js/main.js @@ -13,7 +13,8 @@ document.getElementById('submitBtn').addEventListener('click', function () { participantId: participantId }; - fetch('/tool/lti/result/docker', { +//TODO payload не нужен, убрать + fetch('/tool/lti/task/submit', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) diff --git a/src/test/java/ru/oa2/lti/ScopeTest.java b/src/test/java/ru/oa2/lti/ScopeTest.java index 9754488..901f6ce 100644 --- a/src/test/java/ru/oa2/lti/ScopeTest.java +++ b/src/test/java/ru/oa2/lti/ScopeTest.java @@ -1,7 +1,7 @@ package ru.oa2.lti; import org.junit.jupiter.api.Test; -import ru.oa2.lti.service.jwt.Scope; +import ru.oa2.lti.domain.model.auth.Scope; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; diff --git a/src/test/java/ru/oa2/lti/infrastructure/RunnerTest.java b/src/test/java/ru/oa2/lti/infrastructure/RunnerTest.java index aaf6d65..b8e860f 100644 --- a/src/test/java/ru/oa2/lti/infrastructure/RunnerTest.java +++ b/src/test/java/ru/oa2/lti/infrastructure/RunnerTest.java @@ -3,8 +3,8 @@ package ru.oa2.lti.infrastructure; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import ru.oa2.lti.infrastructure.runner.Runner; -import ru.oa2.lti.infrastructure.runner.RunnerImpl; +import ru.oa2.lti.application.infrastructure.runner.Runner; +import ru.oa2.lti.application.infrastructure.runner.RunnerImpl; import java.util.UUID; diff --git a/src/test/java/ru/oa2/lti/jwt/IdTokenTest.java b/src/test/java/ru/oa2/lti/jwt/IdTokenTest.java index cd2c160..7db0c98 100644 --- a/src/test/java/ru/oa2/lti/jwt/IdTokenTest.java +++ b/src/test/java/ru/oa2/lti/jwt/IdTokenTest.java @@ -3,9 +3,9 @@ package ru.oa2.lti.jwt; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import ru.oa2.lti.config.AppConfig; -import ru.oa2.lti.service.jwt.JwtService; -import ru.oa2.lti.service.jwt.JwtServiceImpl; +import ru.oa2.lti.application.config.AppConfig; +import ru.oa2.lti.application.service.jwt.JwtService; +import ru.oa2.lti.application.service.jwt.JwtServiceImpl; @SpringBootTest(classes = {AppConfig.class, JwtServiceImpl.class}) public class IdTokenTest {