Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,6 @@ public boolean finishMatch(UUID matchId, UUID winnerId) {
}

public Problem pickProblemOfOptions(Map<Category, String> options) {
// SQL в доменной модели — это ЯЗЫК (Category.Language == SQL), а не ProblemType.
// Поэтому SQL-задачу определяем по выбранному языку, а не по ProblemType.
String language = options.get(Category.Language);
String problemType = options.get(Category.ProblemType);
String problemLevel = options.getOrDefault(Category.ProblemLevel, "EASY").toUpperCase();
Expand All @@ -110,8 +108,7 @@ public Problem pickProblemOfOptions(Map<Category, String> options) {
return sqlProblem;
}

// Алгоритмическая задача: тип берём из ProblemType (ALGORITHM/MATH/DATA_STRUCTURES),
// по умолчанию ALGORITHM.

String algoType = (problemType != null) ? problemType : "ALGORITHM";
Problem algoProblem = problemService.getOrCreateRandomAlgoProblem(algoType, problemLevel);
log.info("Selected ALGO problem: id={}, type={}", algoProblem.getId(), algoProblem.getType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ public Artefactik0Client(@Value("${artefactik0.base-url}") String baseUrl) {
.build();
}

// Создать задачу в Artefactik0, вернуть её id
public Long createProblem(CreateProblemRequest request) {
try {
String body = objectMapper.writeValueAsString(request);
Expand All @@ -47,10 +46,9 @@ public Long createProblem(CreateProblemRequest request) {
}
}

// Получить тесты задачи по её id в Artefactik0
public List<TestCase> getTests(Long problemId) {
try {
// Используем ParameterizedTypeReference для получения списка

List<TestCase> tests = restClient.get()
.uri("/api/problems/" + problemId + "/tests")
.retrieve()
Expand All @@ -73,7 +71,7 @@ public List<TestCase> getTests(Long problemId) {
*/
public RandomProblemResponse getRandomProblem(String type, String level) {
try {
// Пока type не поддерживается, но передаём для будущей совместимости

String uri = UriComponentsBuilder.fromPath("/api/problems/random")
.queryParam("type", type.toUpperCase())
.queryParam("complexity", level.toUpperCase())
Expand All @@ -89,16 +87,13 @@ public RandomProblemResponse getRandomProblem(String type, String level) {
}
}

// ── DTOs ──────────────────────────────────────────────────────


// DTO для ответа (только нужные поля)
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public static class RandomProblemResponse {
private Long id;
private String name;
private String level; // EASY, MEDIUM, HARD
private String level;
}

@Data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public SqlServiceClient(@Value("${sqlservice.base-url}") String baseUrl) {
.build();
}



public Long submitSolution(Long taskId, String userId, String query, UUID matchId) {
try {
SubmitRequest request = new SubmitRequest();
Expand All @@ -43,28 +45,34 @@ public Long submitSolution(Long taskId, String userId, String query, UUID matchI
.retrieve()
.body(String.class);

// SqlService возвращает ApiResponse<Long>, где data — это сразу submissionId
log.info("SqlService submit raw response: {}", raw);


JsonNode root = objectMapper.readTree(raw);
if (!root.has("success") || !root.get("success").asBoolean()) {
String error = root.has("error") ? root.get("error").asText() : "Unknown error";
throw new RuntimeException("SqlService error: " + error);
}
long id = root.get("data").asLong(); // <-- чисто число, а не объект
long id = root.get("data").asLong();
log.info("SqlService accepted submission id={}", id);
return id;
} catch (Exception e) {
throw new RuntimeException("Failed to submit SQL solution", e);
}
}



public SubmissionStatus getSubmissionStatus(Long submissionId) {
try {
String raw = restClient.get()
.uri("/sqlservice/submissions/" + submissionId)
.retrieve()
.body(String.class);

// SqlService возвращает ApiResponse<SubmissionStatusDto>, где data — объект
log.debug("SqlService status raw response: {}", raw);


JsonNode root = objectMapper.readTree(raw);
if (!root.has("success") || !root.get("success").asBoolean()) {
String error = root.has("error") ? root.get("error").asText() : "Unknown error";
Expand All @@ -77,6 +85,8 @@ public SubmissionStatus getSubmissionStatus(Long submissionId) {
}
}



public RandomSqlTaskResponse getRandomTask(String level) {
try {
String raw = restClient.get()
Expand All @@ -101,6 +111,8 @@ public RandomSqlTaskResponse getRandomTask(String level) {
}
}



@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public static class RandomSqlTaskResponse {
Expand All @@ -123,12 +135,10 @@ public static class SubmitResponse {
private Long id;
}



@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public static class SubmissionStatus {
private Long id;
private Long submissionId;
private String status;
private String verdict;
private Long executionTimeMs;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,52 +33,18 @@ public class ProblemController {
private final SqlServiceClient sqlServiceClient;
private final MatchService matchService;

// ── Создание задач ────────────────────────────────────────────

// POST /problems/algo — создать алго-задачу (регистрирует в Artefactik0)
@PostMapping("/algo")
public ResponseEntity<Problem> createAlgoProblem(
@RequestBody CreateAlgoProblemRequest request) {
return ResponseEntity.ok(problemService.createAlgoProblem(request));
}

// POST /problems/sql — зарегистрировать SQL-задачу (уже созданную в SqlService)
@PostMapping("/sql")
public ResponseEntity<Problem> registerSqlProblem(
@RequestBody RegisterSqlProblemRequest request) {
return ResponseEntity.ok(problemService.registerSqlProblem(request));
}

// ── Отправка решений ──────────────────────────────────────────

// POST /problems/{id}/submit — отправить код (тип задачи определяется автоматически)
// @PostMapping("/{id}/submit")
// public ResponseEntity<String> submit(
// @AuthenticationPrincipal User user,
// @PathVariable Long id,
// @RequestParam(defaultValue = "62") int languageId,
// @RequestBody String sourceCode) {
// UUID userId = user != null
// ? userService.getIdByEmail(user.getEmail())
// : UUID.randomUUID();
// return ResponseEntity.ok(problemService.submitSolution(userId, id, sourceCode, languageId));
// }

// POST /problems/{id}/submit/file — отправить файл с кодом
// @PostMapping(value = "/{id}/submit/file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
// public ResponseEntity<String> submitFile(
// @AuthenticationPrincipal User user,
// @PathVariable Long id,
// @RequestParam int languageId,
// @RequestParam MultipartFile file
//
// ) throws IOException {
// String sourceCode = new String(file.getBytes(), StandardCharsets.UTF_8);
// UUID userId = userService.getIdByEmail(user.getEmail());
// return ResponseEntity.ok(
// problemService.submitSolution(userId, id, sourceCode, languageId));
// }

@PostMapping(value = "/submit/file", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<String> submitFileByMatch(
@AuthenticationPrincipal User user,
Expand All @@ -90,7 +56,6 @@ public ResponseEntity<String> submitFileByMatch(
return ResponseEntity.badRequest().body("Match not found");
}

// Читаем файл
String sourceCode = new String(file.getBytes(), StandardCharsets.UTF_8);
log.info("Received file for match {}: size={}, content (first 100 chars): {}",
matchId, sourceCode.length(), sourceCode.substring(0, Math.min(100, sourceCode.length())));
Expand All @@ -108,11 +73,6 @@ public ResponseEntity<String> submitFileByMatch(
return ResponseEntity.ok(result);
}

// ── Статус посылки ────────────────────────────────────────────

// GET /problems/submissions/{ref}/status
// ref = "123" → ALGO-посылка, смотрим в локальной БД
// ref = "sql:123" → SQL-посылка, проксируем в SqlService
@GetMapping("/submissions/{submissionRef}/status")
public ResponseEntity<String> getStatus(@PathVariable String submissionRef) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class ProblemService {
private final SubmissionTestRepository submissionTestRepository;
private final S3Repository s3Repository;

// Создать ALGO-задачу: регистрируем в Artefactik0, сохраняем externalId

public Problem createAlgoProblem(CreateAlgoProblemRequest request) {
Artefactik0Client.CreateProblemRequest artefaktRequest =
new Artefactik0Client.CreateProblemRequest();
Expand All @@ -51,7 +51,7 @@ public Problem createAlgoProblem(CreateAlgoProblemRequest request) {
return problemRepository.save(problem);
}

// Зарегистрировать SQL-задачу: задача уже есть в SqlService, просто сохраняем ссылку

public Problem registerSqlProblem(RegisterSqlProblemRequest request) {
Problem problem = new Problem();
problem.setName(request.getName());
Expand All @@ -61,21 +61,21 @@ public Problem registerSqlProblem(RegisterSqlProblemRequest request) {
return problemRepository.save(problem);
}

// Отправить решение — ветвление по типу задачи

public String submitSolution(UUID userId, UUID matchId , Long problemId, String sourceCode, int languageId) {
Problem problem = problemRepository.findById(problemId)
.orElseThrow(() -> new RuntimeException("Problem not found: " + problemId));

return switch (problem.getType()) {
case ALGORITHM -> submitAlgo(userId, problem, sourceCode, languageId , matchId);
case SQL -> submitSql(userId, problem, sourceCode , matchId);
//TODO ( не понятно что к чему )

case MATH -> null;
case DATA_STRUCTURES -> null;
};
}

// ALGO: тесты из Artefactik0 → каждый тест в Judge0

private String submitAlgo(UUID userId, Problem problem, String sourceCode, int languageId , UUID matchId) {
List<Artefactik0Client.TestCase> tests =
artefactik0Client.getTests(problem.getExternalId());
Expand Down Expand Up @@ -118,7 +118,7 @@ private String submitAlgo(UUID userId, Problem problem, String sourceCode, int l
return saved.getId().toString();
}

// SQL: полностью делегируем в SqlService

private String submitSql(UUID userId, Problem problem, String query, UUID matchId) {
if (query == null || query.isBlank()) {
throw new RuntimeException("SQL query cannot be empty");
Expand All @@ -132,18 +132,17 @@ private String submitSql(UUID userId, Problem problem, String query, UUID matchI
);
log.info("SQL submission delegated, sqlSubmissionId={}", sqlSubmissionId);

// Создаём локальную запись — чтобы polling и SubmissionController работали
Submission sub = new Submission();
sub.setProblemId(problem.getId());
sub.setUserId(userId);
sub.setMatchId(matchId);
sub.setLanguageId(0); // SQL не имеет languageId
sub.setLanguageId(0);
sub.setStatus(Submission.Status.IN_QUEUE);
sub.setSqlSubmissionId(sqlSubmissionId); // новое поле — см. ниже
sub.setSqlSubmissionId(sqlSubmissionId);
Submission saved = submissionRepository.save(sub);

log.info("Local SQL submission {} created, sqlSubmissionId={}", saved.getId(), sqlSubmissionId);
return saved.getId().toString(); // возвращаем локальный id, не "sql:123"
return saved.getId().toString();
}

/**
Expand All @@ -153,19 +152,16 @@ private String submitSql(UUID userId, Problem problem, String query, UUID matchI
*/
@Transactional
public Problem getOrCreateRandomAlgoProblem(String type, String level) {
// 1. Запросить случайную задачу из Artefactik0
Artefactik0Client.RandomProblemResponse external =
artefactik0Client.getRandomProblem(type, level);

// 2. Преобразовать строковый тип в enum (пока заглушка -> ALGORITHM)
ProblemType problemType;
try {
problemType = ProblemType.valueOf(type.toUpperCase());
} catch (IllegalArgumentException e) {
problemType = ProblemType.ALGORITHM;
}

// 3. Поиск в локальной БД
ProblemType finalProblemType = problemType;
return problemRepository.findByExternalIdAndType(external.getId(), problemType)
.orElseGet(() -> {
Expand All @@ -185,7 +181,7 @@ public Problem getOrCreateRandomAlgoProblem(String type, String level) {
*/
public Problem getOrCreateRandomSqlProblem(String level) {
List<String> levelsToTry = Arrays.asList(level.toUpperCase(), "MEDIUM", "EASY");
// используем LinkedHashSet для уникальности и сохранения порядка

Set<String> uniqueLevels = new LinkedHashSet<>(levelsToTry);

for (String lvl : uniqueLevels) {
Expand Down
Loading
Loading