From 4aa477555d3b7c08c391525f23d911fb7294c84d Mon Sep 17 00:00:00 2001 From: Marcel Date: Fri, 17 Apr 2026 21:18:27 +0200 Subject: [PATCH] refactor(ocr): return TrainingInfoResponse directly from getTrainingInfo endpoint Remove the intermediate Map and return the typed record directly so OpenAPI codegen produces a concrete TypeScript type. Fixes lastRun serializing as {} (empty object) instead of null when no training run exists. Co-Authored-By: Claude Sonnet 4.6 --- .../familienarchiv/controller/OcrController.java | 16 ++-------------- .../controller/OcrControllerTest.java | 12 ++++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/src/main/java/org/raddatz/familienarchiv/controller/OcrController.java b/backend/src/main/java/org/raddatz/familienarchiv/controller/OcrController.java index cb48caca..4ada18e4 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/controller/OcrController.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/controller/OcrController.java @@ -27,7 +27,6 @@ import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBo import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import jakarta.validation.Valid; -import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -131,19 +130,8 @@ public class OcrController { @GetMapping("/api/ocr/training-info") @RequirePermission(Permission.ADMIN) - public Map getTrainingInfo() { - OcrTrainingService.TrainingInfoResponse info = ocrTrainingService.getTrainingInfo(); - - Map result = new HashMap<>(); - result.put("availableBlocks", info.availableBlocks()); - result.put("totalOcrBlocks", info.totalOcrBlocks()); - result.put("availableDocuments", info.availableDocuments()); - result.put("availableSegBlocks", info.availableSegBlocks()); - result.put("ocrServiceAvailable", info.ocrServiceAvailable()); - result.put("lastRun", info.lastRun() != null ? info.lastRun() : Map.of()); - result.put("runs", info.runs()); - result.put("personNames", info.personNames()); - return result; + public OcrTrainingService.TrainingInfoResponse getTrainingInfo() { + return ocrTrainingService.getTrainingInfo(); } private UUID resolveUserId(Authentication authentication) { diff --git a/backend/src/test/java/org/raddatz/familienarchiv/controller/OcrControllerTest.java b/backend/src/test/java/org/raddatz/familienarchiv/controller/OcrControllerTest.java index 5313b267..e65e490c 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/controller/OcrControllerTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/controller/OcrControllerTest.java @@ -264,6 +264,18 @@ class OcrControllerTest { .andExpect(jsonPath("$.personNames." + personId).value("Max Mustermann")); } + @Test + @WithMockUser(authorities = "ADMIN") + void getTrainingInfo_serializes_null_lastRun_as_json_null() throws Exception { + OcrTrainingService.TrainingInfoResponse info = + new OcrTrainingService.TrainingInfoResponse(0, 0, 0, 0, false, null, List.of(), Map.of()); + when(ocrTrainingService.getTrainingInfo()).thenReturn(info); + + mockMvc.perform(get("/api/ocr/training-info")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lastRun").doesNotExist()); + } + @Test @WithMockUser(authorities = "READ_ALL") void getDocumentOcrStatus_returnsNone_whenNoOcrJobExists() throws Exception {