From 23ea2ed09f1e08e02b064233f89c37c8e6ffb714 Mon Sep 17 00:00:00 2001 From: Anton Dzyk Date: Wed, 24 Dec 2025 12:06:53 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=80=D0=B5=D0=B6=D0=B8=D0=BC=D0=B0=20?= =?UTF-8?q?=D0=B4=D0=BB=D1=8F=20=D1=83=D1=87=D0=B8=D1=82=D0=B5=D0=BB=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- debug/tasks_scripts/1.sh | 287 ++++++++++++++++++ .../java/ru/oa2/lti/ApplicationService.java | 20 +- .../oa2/lti/controller/LaunchController.java | 11 + .../oa2/lti/controller/ResultController.java | 1 - src/main/resources/templates/task-editor.html | 216 +++++++++++++ 5 files changed, 522 insertions(+), 13 deletions(-) create mode 100755 debug/tasks_scripts/1.sh create mode 100644 src/main/resources/templates/task-editor.html diff --git a/debug/tasks_scripts/1.sh b/debug/tasks_scripts/1.sh new file mode 100755 index 0000000..52bb63e --- /dev/null +++ b/debug/tasks_scripts/1.sh @@ -0,0 +1,287 @@ +#!/bin/bash + +# Скрипт для создания группы, репозитория и копирования кода в GitLab +# с назначением прав пользователю из Keycloak + +set -e # Прерывать выполнение при ошибках + +# === КОНФИГУРАЦИЯ === + +# GitLab Private Token с правами администратора +PRIVATE_TOKEN=$1 +# Пользователь из Keycloak (должен существовать в GitLab) +KEYCLOAK_USERNAME=$2 +USER_ID=${KEYCLOAK_USERNAME} + +GITLAB_URL="https://gitlab.oa2.ru" # URL вашего GitLab + +# Данные для новой группы и репозитория +GROUP_NAME="group-${USER_ID}" +GROUP_PATH="group-${USER_ID}" # Может отличаться от имени +GROUP_DESCRIPTION="Группа для пользователя ${USER_ID}" + +# Данные для нового репозитория +PROJECT_NAME="task1" +PROJECT_DESCRIPTION="Репозиторий с кодом task1" + +# Внешний репозиторий для копирования +SOURCE_REPO_URL="https://git.oa2.ru/dzyk/task1" # Замените на реальный URL + +# Уровень доступа для пользователя (owner = 50) +ACCESS_LEVEL=50 + +# Временная директория для клонирования +TEMP_DIR="/tmp/gitlab-migration-$(date +%s)" + +# === ФУНКЦИИ === + +# Функция для логирования +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} + +# Функция для выполнения HTTP запросов к GitLab API +gitlab_api() { + local method=$1 + local endpoint=$2 + local data=$3 + + local curl_cmd="curl -s -X $method \ + '$GITLAB_URL/api/v4$endpoint' \ + -H 'Private-Token: $PRIVATE_TOKEN' \ + -H 'Content-Type: application/json'" + + if [ ! -z "$data" ]; then + curl_cmd="$curl_cmd -d '$data'" + fi + + eval $curl_cmd +} + +# Функция для проверки ошибок API +check_api_error() { + local response=$1 + local operation=$2 + + if echo "$response" | jq -e '.error' > /dev/null 2>&1; then + error_msg=$(echo "$response" | jq -r '.error') + log "Ошибка при $operation: $error_msg" + return 1 + fi + + if echo "$response" | jq -e '.message' > /dev/null 2>&1; then + error_msg=$(echo "$response" | jq -r '.message') + if [ "$error_msg" != "null" ] && [ ! -z "$error_msg" ]; then + log "Ошибка при $operation: $error_msg" + return 1 + fi + fi + + return 0 +} + +# === ОСНОВНОЙ СКРИПТ === + +log "Начало выполнения скрипта" + +# 1. Проверка зависимостей +log "Проверка зависимостей..." +for cmd in curl jq git; do + if ! command -v $cmd &> /dev/null; then + log "Ошибка: $cmd не установлен" + exit 1 + fi +done +log "Все зависимости установлены" + +# 2. Поиск пользователя из Keycloak +log "Поиск пользователя '$KEYCLOAK_USERNAME' в GitLab..." +user_search=$(gitlab_api "GET" "/users?username=$KEYCLOAK_USERNAME") +if ! check_api_error "$user_search" "поиске пользователя"; then + exit 1 +fi + +user_id=$(echo "$user_search" | jq -r '.[0].id') +user_username=$(echo "$user_search" | jq -r '.[0].username') + +if [ "$user_id" = "null" ] || [ -z "$user_id" ]; then + log "Ошибка: Пользователь '$KEYCLOAK_USERNAME' не найден в GitLab" + log "Убедитесь, что пользователь вошел через Keycloak хотя бы один раз" + exit 1 +fi + +log "Найден пользователь: $user_username (ID: $user_id)" + +# 4. Создание группы +log "Проверка существования группы '$GROUP_NAME'..." +group_check=$(gitlab_api "GET" "/groups/$GROUP_PATH") +if echo "$group_check" | jq -e '.id' > /dev/null 2>&1; then + group_id=$(echo "$group_check" | jq -r '.id') + log "Группа '$GROUP_NAME' уже существует (ID: $group_id)" +else + log "Создание группы '$GROUP_NAME'..." + group_data=$(jq -n \ + --arg name "$GROUP_NAME" \ + --arg path "$GROUP_PATH" \ + --arg desc "$GROUP_DESCRIPTION" \ + --arg visibility "private" \ + '{ + name: $name, + path: $path, + description: $desc, + visibility: $visibility, + lfs_enabled: true, + request_access_enabled: true + }') + + create_group=$(gitlab_api "POST" "/groups" "$group_data") + if ! check_api_error "$create_group" "создании группы"; then + exit 1 + fi + + group_id=$(echo "$create_group" | jq -r '.id') + log "Группа создана успешно (ID: $group_id)" +fi + +# 5. Создание проекта в группе +log "Проверка существования проекта '$PROJECT_NAME' в группе..." +project_check=$(gitlab_api "GET" "/projects/$GROUP_PATH%2F$PROJECT_NAME") +if echo "$project_check" | jq -e '.id' > /dev/null 2>&1; then + project_id=$(echo "$project_check" | jq -r '.id') + log "Проект '$PROJECT_NAME' уже существует (ID: $project_id)" +else + log "Создание проекта '$PROJECT_NAME' в группе..." + project_data=$(jq -n \ + --arg name "$PROJECT_NAME" \ + --arg path "$PROJECT_NAME" \ + --arg desc "$PROJECT_DESCRIPTION" \ + --arg namespace_id "$group_id" \ + --arg visibility "private" \ + '{ + name: $name, + path: $path, + description: $desc, + namespace_id: $namespace_id, + visibility: $visibility, + initialize_with_readme: false, + lfs_enabled: true, + container_registry_enabled: true + }') + + create_project=$(gitlab_api "POST" "/projects" "$project_data") + if ! check_api_error "$create_project" "создании проекта"; then + exit 1 + fi + + project_id=$(echo "$create_project" | jq -r '.id') + project_ssh_url=$(echo "$create_project" | jq -r '.ssh_url_to_repo') + project_http_url=$(echo "$create_project" | jq -r '.http_url_to_repo') + log "Проект создан успешно (ID: $project_id)" + log "URL проекта: $project_http_url" +fi + +# 6. Назначение прав пользователю как owner группы +log "Проверка прав пользователя $user_username в группе..." +group_members=$(gitlab_api "GET" "/groups/$group_id/members") +user_in_group=$(echo "$group_members" | jq --arg user_id "$user_id" '.[] | select(.id == ($user_id|tonumber))') + +if [ -z "$user_in_group" ]; then + log "Назначение прав owner пользователю $user_username в группе..." + member_data=$(jq -n \ + --arg user_id "$user_id" \ + --arg access_level "$ACCESS_LEVEL" \ + '{ + user_id: $user_id, + access_level: ($access_level|tonumber) + }') + + add_member=$(gitlab_api "POST" "/groups/$group_id/members" "$member_data") + if ! check_api_error "$add_member" "добавлении пользователя в группу"; then + exit 1 + fi + + log "Пользователю $user_username назначены права owner в группе" +else + current_access=$(echo "$user_in_group" | jq -r '.access_level') + if [ "$current_access" != "$ACCESS_LEVEL" ]; then + log "Обновление прав пользователя $user_username с уровня $current_access на $ACCESS_LEVEL..." + member_data=$(jq -n \ + --arg access_level "$ACCESS_LEVEL" \ + '{ + access_level: ($access_level|tonumber) + }') + + update_member=$(gitlab_api "PUT" "/groups/$group_id/members/$user_id" "$member_data") + if ! check_api_error "$update_member" "обновлении прав пользователя"; then + exit 1 + fi + log "Права пользователя обновлены" + else + log "Пользователь $user_username уже имеет права owner в группе" + fi +fi + +# 7. Клонирование и копирование кода +log "Создание временной директории: $TEMP_DIR" +mkdir -p "$TEMP_DIR" +cd "$TEMP_DIR" + +log "Клонирование исходного репозитория: $SOURCE_REPO_URL" +if ! git clone --bare "$SOURCE_REPO_URL" source-repo.git; then + log "Ошибка при клонировании исходного репозитория" + exit 1 +fi + +log "Клонирование целевого репозитория GitLab" +# Получаем URL репозитория с токеном для записи +repo_url_with_token=$(echo "$project_http_url" | sed "s|https://|https://gitlab-ci-token:$PRIVATE_TOKEN@|") +if ! git clone "$repo_url_with_token" target-repo; then + log "Ошибка при клонировании целевого репозитория" + exit 1 +fi + +cd target-repo + +log "Добавление remote исходного репозитория" +git remote add source ../source-repo.git + +log "Получение данных из исходного репозитория" +git fetch source + +log "Объединение всех веток из исходного репозитория" +for branch in $(git branch -r | grep 'source/' | sed 's|source/||'); do + if [ "$branch" != "HEAD" ] && [ "$branch" != "->" ]; then + log " Копирование ветки: $branch" + git checkout -b "$branch" "source/$branch" 2>/dev/null || git branch "$branch" "source/$branch" + fi +done + +# Возвращаемся в основную ветку (если есть) +if git show-ref --verify --quiet refs/heads/main; then + git checkout main +elif git show-ref --verify --quiet refs/heads/master; then + git checkout master +fi + +log "Отправка всех веток в GitLab" +git push --all origin +git push --tags origin + +log "Очистка временных файлов" +cd / +rm -rf "$TEMP_DIR" + +# 8. Проверка результата +log "Проверка созданной структуры..." +final_check=$(gitlab_api "GET" "/projects/$project_id") +project_name=$(echo "$final_check" | jq -r '.name_with_namespace') +web_url=$(echo "$final_check" | jq -r '.web_url') + +log "=== ОТЧЕТ ===" +log "Группа: $GROUP_NAME (ID: $group_id)" +log "Проект: $project_name (ID: $project_id)" +log "URL проекта: $web_url" +log "Пользователь с правами owner: $user_username" +log "Код скопирован из: $SOURCE_REPO_URL" +log "" +log "Скрипт успешно выполнен!" \ No newline at end of file diff --git a/src/main/java/ru/oa2/lti/ApplicationService.java b/src/main/java/ru/oa2/lti/ApplicationService.java index 719bba1..8e3539f 100644 --- a/src/main/java/ru/oa2/lti/ApplicationService.java +++ b/src/main/java/ru/oa2/lti/ApplicationService.java @@ -10,6 +10,7 @@ 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; @@ -55,18 +56,13 @@ public class ApplicationService { } } - public String saveResult(String body) { + public ResultResponse updateTask(String body) { + return new ResultResponse("success"); + } - return "{\n" + - " \"success\": true,\n" + - " \"message\": \"Результат успешно получен и обработан\",\n" + - " \"data\": {\n" + - " \"contextId\": \"ctx-12345\",\n" + - " \"participantId\": \"usr-67890\",\n" + - " \"submittedText\": \"console.log('Hello');\",\n" + - " \"timestamp\": \"2025-12-14T17:55:30Z\",\n" + - " \"status\": \"processed\"\n" + - " }\n" + - "}"; + public ResultResponse saveResult(String body) { + + //TODO заполнять из результатов проверок check скрипта + return new ResultResponse("success"); } } diff --git a/src/main/java/ru/oa2/lti/controller/LaunchController.java b/src/main/java/ru/oa2/lti/controller/LaunchController.java index 96fc49f..ceb3af5 100644 --- a/src/main/java/ru/oa2/lti/controller/LaunchController.java +++ b/src/main/java/ru/oa2/lti/controller/LaunchController.java @@ -3,6 +3,7 @@ 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.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; @@ -11,6 +12,8 @@ import ru.oa2.lti.infrastructure.LMSService; import ru.oa2.lti.model.LtiLogin; import ru.oa2.lti.service.jwt.Payload; +import java.util.Objects; + @Slf4j @Controller @RequestMapping("/tool/lti") @@ -63,6 +66,11 @@ public class LaunchController { return "redirect:/tool/lti/select"; } + @PostMapping("/task") + public ResponseEntity updateTask() { + + return service.updateTask("TODO"); + } @GetMapping("/task") public String showDockerTas(Model model, @@ -81,6 +89,9 @@ public class LaunchController { model.addAttribute("description", data); } + if (Objects.requireNonNull(payload).getCoach()) { + return "task-editor"; + } return "task"; } diff --git a/src/main/java/ru/oa2/lti/controller/ResultController.java b/src/main/java/ru/oa2/lti/controller/ResultController.java index 34dc8e0..0be247a 100644 --- a/src/main/java/ru/oa2/lti/controller/ResultController.java +++ b/src/main/java/ru/oa2/lti/controller/ResultController.java @@ -55,7 +55,6 @@ public class ResultController { jwtService.getTokenPayload(idToken) ); - //TODO возвращать json return ResponseEntity .accepted() .body(service.saveResult(body)); diff --git a/src/main/resources/templates/task-editor.html b/src/main/resources/templates/task-editor.html new file mode 100644 index 0000000..cfd6cde --- /dev/null +++ b/src/main/resources/templates/task-editor.html @@ -0,0 +1,216 @@ + + + + + + Редактор задачи LTI + + + + + + +
+ + +
+

Редактор задачи

+
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + + +
+ + + + + + + + + + + \ No newline at end of file