fix(ocr): validate personId in TriggerSenderTrainingDTO — returns 400 not 500 on null
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -155,7 +155,7 @@ public class OcrController {
|
||||
@PostMapping("/api/ocr/train-sender")
|
||||
@ResponseStatus(HttpStatus.ACCEPTED)
|
||||
@RequirePermission(Permission.ADMIN)
|
||||
public OcrTrainingRun triggerSenderTraining(@RequestBody TriggerSenderTrainingDTO dto) {
|
||||
public OcrTrainingRun triggerSenderTraining(@Valid @RequestBody TriggerSenderTrainingDTO dto) {
|
||||
OcrTrainingRun run = senderModelService.triggerManualSenderTraining(dto.personId());
|
||||
if (run.getStatus() == TrainingStatus.RUNNING) {
|
||||
senderModelService.runSenderTraining(dto.personId());
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
package org.raddatz.familienarchiv.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record TriggerSenderTrainingDTO(UUID personId) {}
|
||||
public record TriggerSenderTrainingDTO(
|
||||
@NotNull
|
||||
@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
UUID personId
|
||||
) {}
|
||||
|
||||
@@ -356,6 +356,79 @@ class OcrControllerTest {
|
||||
.andExpect(jsonPath("$.personNames." + personId).value("Anna Müller"));
|
||||
}
|
||||
|
||||
// ─── POST /api/ocr/train-sender ───────────────────────────────────────────
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ADMIN")
|
||||
void triggerSenderTraining_returns400_whenPersonIdIsNull() throws Exception {
|
||||
mockMvc.perform(post("/api/ocr/train-sender")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"personId\":null}"))
|
||||
.andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
void triggerSenderTraining_returns401_whenUnauthenticated() throws Exception {
|
||||
mockMvc.perform(post("/api/ocr/train-sender")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"personId\":\"" + UUID.randomUUID() + "\"}"))
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "READ_ALL")
|
||||
void triggerSenderTraining_returns403_whenNotAdmin() throws Exception {
|
||||
mockMvc.perform(post("/api/ocr/train-sender")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"personId\":\"" + UUID.randomUUID() + "\"}"))
|
||||
.andExpect(status().isForbidden());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ADMIN")
|
||||
void triggerSenderTraining_returns404_whenPersonNotFound() throws Exception {
|
||||
UUID unknownId = UUID.randomUUID();
|
||||
when(senderModelService.triggerManualSenderTraining(unknownId))
|
||||
.thenThrow(DomainException.notFound(ErrorCode.PERSON_NOT_FOUND, "Person not found"));
|
||||
|
||||
mockMvc.perform(post("/api/ocr/train-sender")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"personId\":\"" + unknownId + "\"}"))
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ADMIN")
|
||||
void triggerSenderTraining_returns202_withRunning_run() throws Exception {
|
||||
UUID personId = UUID.randomUUID();
|
||||
OcrTrainingRun run = OcrTrainingRun.builder()
|
||||
.id(UUID.randomUUID()).status(TrainingStatus.RUNNING)
|
||||
.personId(personId).blockCount(5).documentCount(0).modelName("sender_" + personId).build();
|
||||
when(senderModelService.triggerManualSenderTraining(personId)).thenReturn(run);
|
||||
|
||||
mockMvc.perform(post("/api/ocr/train-sender")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"personId\":\"" + personId + "\"}"))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$.status").value("RUNNING"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "ADMIN")
|
||||
void triggerSenderTraining_returns202_withQueued_run_whenAnotherRunning() throws Exception {
|
||||
UUID personId = UUID.randomUUID();
|
||||
OcrTrainingRun run = OcrTrainingRun.builder()
|
||||
.id(UUID.randomUUID()).status(TrainingStatus.QUEUED)
|
||||
.personId(personId).blockCount(5).documentCount(0).modelName("sender_" + personId).build();
|
||||
when(senderModelService.triggerManualSenderTraining(personId)).thenReturn(run);
|
||||
|
||||
mockMvc.perform(post("/api/ocr/train-sender")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("{\"personId\":\"" + personId + "\"}"))
|
||||
.andExpect(status().isAccepted())
|
||||
.andExpect(jsonPath("$.status").value("QUEUED"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser(authorities = "READ_ALL")
|
||||
void getDocumentOcrStatus_returnsNone_whenNoOcrJobExists() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user