diff --git a/src/main/java/de/assecutor/votianlt/controller/MessageController.java b/src/main/java/de/assecutor/votianlt/controller/MessageController.java index 050add6..d4de0b6 100644 --- a/src/main/java/de/assecutor/votianlt/controller/MessageController.java +++ b/src/main/java/de/assecutor/votianlt/controller/MessageController.java @@ -2,11 +2,16 @@ package de.assecutor.votianlt.controller; import de.assecutor.votianlt.dto.AppLoginRequest; import de.assecutor.votianlt.dto.AppLoginResponse; +import de.assecutor.votianlt.dto.JobWithRelatedDataDTO; import de.assecutor.votianlt.model.AppUser; +import de.assecutor.votianlt.model.CargoItem; import de.assecutor.votianlt.model.Job; +import de.assecutor.votianlt.model.TaskEntry; import de.assecutor.votianlt.pages.service.AppUserService; import de.assecutor.votianlt.repository.AppUserRepository; +import de.assecutor.votianlt.repository.CargoItemRepository; import de.assecutor.votianlt.repository.JobRepository; +import de.assecutor.votianlt.repository.TaskRepository; import lombok.extern.slf4j.Slf4j; import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.SendTo; @@ -40,6 +45,12 @@ public class MessageController { @Autowired private JobRepository jobRepository; + @Autowired + private CargoItemRepository cargoItemRepository; + + @Autowired + private TaskRepository taskRepository; + /** * Handles messages sent to /app/message and broadcasts them to all subscribers of /topic/messages */ @@ -151,20 +162,20 @@ public class MessageController { return response; } - AppLoginResponse response = new AppLoginResponse(true, "Anmeldung erfolgreich", user.getId() != null ? user.getId().toHexString() : null); + AppLoginResponse response = new AppLoginResponse(true, "Anmeldung erfolgreich", user.getIdAsString()); log.info("STOMP Response for '/app/auth/login' sent to '/user/queue/auth': success={}, message='{}', appUserId='{}'", true, "Anmeldung erfolgreich", response.getAppUserId()); return response; } /** - * Endpoint to retrieve jobs assigned to a specific app user. + * Endpoint to retrieve jobs assigned to a specific app user with related cargo items and tasks. * Client sends to /app/jobs/assigned with payload { appUserId }. * The response is sent back to the requesting user on /user/queue/jobs */ @MessageMapping("/jobs/assigned") @SendToUser("/queue/jobs") - public List handleGetAssignedJobs(Map request) { + public List handleGetAssignedJobs(Map request) { log.info("STOMP Endpoint '/app/jobs/assigned' called with data: {}", request); if (request == null || !request.containsKey("appUserId")) { @@ -180,9 +191,19 @@ public class MessageController { // Find jobs assigned to this app user List assignedJobs = jobRepository.findByAppUser(appUserId); - log.info("STOMP Response for '/app/jobs/assigned' sent to '/user/queue/jobs': {} jobs found for appUserId='{}'", - assignedJobs.size(), appUserId); - return assignedJobs; + // For each job, fetch related cargo items and tasks + List jobsWithRelatedData = assignedJobs.stream() + .map(job -> { + List cargoItems = cargoItemRepository.findByJobId(job.getId()); + List tasks = taskRepository.findByJobId(job.getId()); + return new JobWithRelatedDataDTO(job, cargoItems, tasks); + }) + .toList(); + + log.info("STOMP Response for '/app/jobs/assigned' sent to '/user/queue/jobs': {} jobs with related data found for appUserId='{}'", + jobsWithRelatedData.size(), appUserId); + + return jobsWithRelatedData; } } \ No newline at end of file diff --git a/src/main/java/de/assecutor/votianlt/dto/JobWithRelatedDataDTO.java b/src/main/java/de/assecutor/votianlt/dto/JobWithRelatedDataDTO.java new file mode 100644 index 0000000..ee2fc6a --- /dev/null +++ b/src/main/java/de/assecutor/votianlt/dto/JobWithRelatedDataDTO.java @@ -0,0 +1,23 @@ +package de.assecutor.votianlt.dto; + +import de.assecutor.votianlt.model.CargoItem; +import de.assecutor.votianlt.model.Job; +import de.assecutor.votianlt.model.TaskEntry; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * DTO for returning job data with related cargo items and tasks. + * This combines Job entity with its associated CargoItems and TaskEntries. + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class JobWithRelatedDataDTO { + private Job job; + private List cargoItems; + private List tasks; +} \ No newline at end of file diff --git a/src/main/java/de/assecutor/votianlt/model/AppUser.java b/src/main/java/de/assecutor/votianlt/model/AppUser.java index e9b22e9..47828a3 100644 --- a/src/main/java/de/assecutor/votianlt/model/AppUser.java +++ b/src/main/java/de/assecutor/votianlt/model/AppUser.java @@ -1,5 +1,7 @@ package de.assecutor.votianlt.model; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.bson.types.ObjectId; import org.springframework.data.annotation.Id; @@ -13,6 +15,7 @@ import java.time.LocalDateTime; public class AppUser { @Id + @JsonIgnore private ObjectId id; @Field("bezeichnung") @@ -62,4 +65,13 @@ public class AppUser { this.erstelltAm = LocalDateTime.now(); this.aktualisiertAm = LocalDateTime.now(); } + + /** + * Returns the ObjectId as string for JSON serialization. + * This ensures that the app user id is returned as a string when users are retrieved via API. + */ + @JsonGetter("id") + public String getIdAsString() { + return id != null ? id.toString() : null; + } } diff --git a/src/main/java/de/assecutor/votianlt/model/CargoItem.java b/src/main/java/de/assecutor/votianlt/model/CargoItem.java index c00860d..beb165e 100644 --- a/src/main/java/de/assecutor/votianlt/model/CargoItem.java +++ b/src/main/java/de/assecutor/votianlt/model/CargoItem.java @@ -1,5 +1,7 @@ package de.assecutor.votianlt.model; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -14,6 +16,7 @@ import org.springframework.data.mongodb.core.mapping.Field; @Document(collection = "cargo_items") public class CargoItem { @Id + @JsonIgnore private ObjectId id; @Field("job_id") @@ -36,5 +39,14 @@ public class CargoItem { @Field("height_mm") private Double heightMm; + + /** + * Returns the ObjectId as string for JSON serialization. + * This ensures that the cargo item id is returned as a string when items are retrieved via API. + */ + @JsonGetter("id") + public String getIdAsString() { + return id != null ? id.toString() : null; + } } diff --git a/src/main/java/de/assecutor/votianlt/model/Job.java b/src/main/java/de/assecutor/votianlt/model/Job.java index 551581c..eb0878f 100644 --- a/src/main/java/de/assecutor/votianlt/model/Job.java +++ b/src/main/java/de/assecutor/votianlt/model/Job.java @@ -1,5 +1,7 @@ package de.assecutor.votianlt.model; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import org.bson.types.ObjectId; import org.springframework.data.annotation.Id; @@ -14,6 +16,7 @@ import java.math.BigDecimal; @Document(collection = "jobs") public class Job { @Id + @JsonIgnore private ObjectId id; // Metadaten @@ -122,4 +125,13 @@ public class Job { // Preis (netto) @Field("price") private BigDecimal price; + + /** + * Returns the ObjectId as string for JSON serialization. + * This ensures that the job id is returned as a string when jobs are retrieved via API. + */ + @JsonGetter("id") + public String getIdAsString() { + return id != null ? id.toString() : null; + } } diff --git a/src/main/java/de/assecutor/votianlt/model/TaskEntry.java b/src/main/java/de/assecutor/votianlt/model/TaskEntry.java index 4deb6a6..0a797ac 100644 --- a/src/main/java/de/assecutor/votianlt/model/TaskEntry.java +++ b/src/main/java/de/assecutor/votianlt/model/TaskEntry.java @@ -1,5 +1,7 @@ package de.assecutor.votianlt.model; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -14,12 +16,32 @@ import org.springframework.data.mongodb.core.mapping.Field; @Document(collection = "tasks") public class TaskEntry { @Id + @JsonIgnore private ObjectId id; @Field("job_id") + @JsonIgnore private ObjectId jobId; @Field("text") private String text; + + /** + * Returns the ObjectId as string for JSON serialization. + * This ensures that the task id is returned as a string when jobs are retrieved via API. + */ + @JsonGetter("id") + public String getIdAsString() { + return id != null ? id.toString() : null; + } + + /** + * Returns the job ObjectId as string for JSON serialization. + * This ensures that the job id is returned as a string instead of ObjectId object. + */ + @JsonGetter("jobId") + public String getJobIdAsString() { + return jobId != null ? jobId.toString() : null; + } } diff --git a/src/test/java/JsonSerializationTest.java b/src/test/java/JsonSerializationTest.java new file mode 100644 index 0000000..eb8496c --- /dev/null +++ b/src/test/java/JsonSerializationTest.java @@ -0,0 +1,60 @@ +import com.fasterxml.jackson.databind.ObjectMapper; +import de.assecutor.votianlt.dto.JobWithRelatedDataDTO; +import de.assecutor.votianlt.model.CargoItem; +import de.assecutor.votianlt.model.Job; +import de.assecutor.votianlt.model.TaskEntry; +import org.bson.types.ObjectId; + +import java.util.List; + +/** + * Simple test to verify JSON serialization of ObjectIds as strings + */ +public class JsonSerializationTest { + + public static void main(String[] args) throws Exception { + System.out.println("[DEBUG_LOG] Testing Job ID serialization..."); + + // Create test data + Job job = new Job(); + job.setId(new ObjectId()); + job.setJobNumber("TEST-001"); + + CargoItem cargo = new CargoItem(); + cargo.setId(new ObjectId()); + cargo.setJobId(job.getId()); + cargo.setDescription("Test cargo"); + + TaskEntry task = new TaskEntry(); + task.setId(new ObjectId()); + task.setJobId(job.getId()); + task.setText("Test task"); + + JobWithRelatedDataDTO dto = new JobWithRelatedDataDTO(job, List.of(cargo), List.of(task)); + + // Serialize to JSON + ObjectMapper mapper = new ObjectMapper(); + String json = mapper.writeValueAsString(dto); + + System.out.println("[DEBUG_LOG] Serialized JSON: " + json); + + // Check if job ID is serialized as string + if (json.contains("\"id\":\"" + job.getId().toString() + "\"")) { + System.out.println("[DEBUG_LOG] ✓ Job ID correctly serialized as string"); + } else if (json.contains("\"id\":{")) { + System.out.println("[DEBUG_LOG] ✗ Job ID serialized as ObjectId object"); + } else { + System.out.println("[DEBUG_LOG] ? Job ID serialization format unclear"); + } + + // Test individual Job serialization + String jobJson = mapper.writeValueAsString(job); + System.out.println("[DEBUG_LOG] Individual Job JSON: " + jobJson); + + if (jobJson.contains("\"id\":\"" + job.getId().toString() + "\"")) { + System.out.println("[DEBUG_LOG] ✓ Individual Job ID correctly serialized as string"); + } else { + System.out.println("[DEBUG_LOG] ✗ Individual Job ID not serialized as string"); + } + } +} \ No newline at end of file