Skip to content
Open
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
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@
<artifactId>spring-boot-docker-compose</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.example.vet1177.dto.request.medicalrecord;



import jakarta.validation.constraints.NotNull;

import java.util.UUID;

// Tilldela handläggare
public record AssignVetRequest(
@NotNull(message = "Veterinär måste anges")
UUID vetId
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.example.vet1177.dto.request.medicalrecord;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import java.util.UUID;

// Skapa nytt ärende
public record CreateMedicalRecordRequest(
@NotBlank(message = "Titel får inte vara tom")
@Size(max = 500, message = "Titel får max vara 500 tecken")
String title,

@Size(max = 5000, message = "Beskrivning får max vara 5000 tecken")
String description,

@NotNull(message = "Djur måste anges")
UUID petId,

@NotNull(message = "Klinik måste anges")
UUID clinicId

) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.example.vet1177.dto.request.medicalrecord;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

// Uppdatera titel och beskrivning
public record UpdateMedicalRecordRequest(
@NotBlank(message = "Titel får inte vara tom")
@Size(max = 500, message = "Titel får max vara 500 tecken")
String title,

@Size(max = 5000, message = "Beskrivning får max vara 5000 tecken")
String description
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.example.vet1177.dto.request.medicalrecord;


import jakarta.validation.constraints.NotNull;
import org.example.vet1177.entities.RecordStatus;

// Uppdatera status
public record UpdateStatusRequest(
@NotNull(message = "Status måste anges")
RecordStatus status
) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.example.vet1177.dto.response.medicalrecord;

import org.example.vet1177.entities.MedicalRecord;
import org.example.vet1177.entities.RecordStatus;

import java.time.Instant;
import java.util.UUID;

//fullständigt svar för getByID:
public record MedicalRecordResponse(
UUID id,
String title,
String description,
RecordStatus status,
UUID petId,
String petName,
String petSpecies,
UUID ownerId,
String ownerName,
UUID clinicId,
String clinicName,
UUID assignedVetId,
String assignedVetName,
UUID createdById,
String createdByName,
Instant createdAt,
Instant updatedAt,
Instant closedAt
) {
public static MedicalRecordResponse from(MedicalRecord record) {
return new MedicalRecordResponse(
record.getId(),
record.getTitle(),
record.getDescription(),
record.getStatus(),
record.getPet().getId(),
record.getPet().getName(),
record.getPet().getSpecies(),
record.getOwner().getId(),
record.getOwner().getName(),
record.getClinic().getId(),
record.getClinic().getName(),
record.getAssignedVet() != null ? record.getAssignedVet().getId() : null,
record.getAssignedVet() != null ? record.getAssignedVet().getName() : null,
record.getCreatedBy().getId(),
record.getCreatedBy().getName(),
record.getCreatedAt(),
record.getUpdatedAt(),
record.getClosedAt()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.example.vet1177.dto.response.medicalrecord;

import org.example.vet1177.entities.MedicalRecord;
import org.example.vet1177.entities.RecordStatus;

import java.time.Instant;
import java.util.UUID;

// Förenklat svar som används i listor
public record MedicalRecordSummaryResponse(
UUID id,
String title,
RecordStatus status,
String petName,
String ownerName,
String assignedVetName,
Instant createdAt
) {
public static MedicalRecordSummaryResponse from(MedicalRecord record) {
return new MedicalRecordSummaryResponse(
record.getId(),
record.getTitle(),
record.getStatus(),
record.getPet().getName(),
record.getOwner().getName(),
record.getAssignedVet() != null ? record.getAssignedVet().getName() : null,
record.getCreatedAt()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,34 @@

import org.example.vet1177.entities.MedicalRecord;
import org.example.vet1177.entities.RecordStatus;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Repository
public interface MedicalRecordRepository extends JpaRepository<MedicalRecord, UUID> {

// Hämta alla ärenden för ett specifikt djur
@EntityGraph(attributePaths = {
"pet", "owner", "clinic", "assignedVet", "createdBy"
})
Optional<MedicalRecord> findById(UUID id);

@EntityGraph(attributePaths = {"pet", "owner", "clinic", "assignedVet", "createdBy"})
List<MedicalRecord> findByPetId(UUID petId);

// Hämta alla ärenden för en ägare
@EntityGraph(attributePaths = {"pet", "owner", "clinic", "assignedVet", "createdBy"})
List<MedicalRecord> findByOwnerId(UUID ownerId);

// Hämta alla ärenden tilldelade en specifik vet
List<MedicalRecord> findByAssignedVetId(UUID vetId);

// Hämta alla ärenden för en klinik
@EntityGraph(attributePaths = {"pet", "owner", "clinic", "assignedVet", "createdBy"})
List<MedicalRecord> findByClinicId(UUID clinicId);

// Hämta ärenden filtrerat på status
List<MedicalRecord> findByStatus(RecordStatus status);

// Kombinerat — ärenden för en klinik med specifik status (användbart för ABAC)
@EntityGraph(attributePaths = {"pet", "owner", "clinic", "assignedVet", "createdBy"})
List<MedicalRecord> findByClinicIdAndStatus(UUID clinicId, RecordStatus status);

List<MedicalRecord> findByAssignedVetId(UUID vetId);
List<MedicalRecord> findByStatus(RecordStatus status);
Comment on lines +33 to +34
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for usages of findByAssignedVetId and findByStatus to determine if they need `@EntityGraph`

echo "=== Usages of findByAssignedVetId ==="
rg -n -C5 'findByAssignedVetId' --type java

echo ""
echo "=== Usages of findByStatus ==="
rg -n -C5 'findByStatus' --type java -g '!*Repository*'

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 1110


🏁 Script executed:

# Search for usages of these methods in all files including tests and other locations
echo "=== All usages of findByAssignedVetId (expanded search) ==="
rg 'findByAssignedVetId' -n --type-list | head -20

echo ""
echo "=== All usages of findByStatus (expanded search) ==="
rg 'findByStatus' -n --type-list | head -20

echo ""
echo "=== Check MedicalRecord entity and response classes ==="
find . -name "*MedicalRecord*" -type f | head -20

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 1641


🏁 Script executed:

# Look for the response converter classes mentioned in the review
rg 'MedicalRecordResponse|MedicalRecordSummaryResponse' -l --type java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 270


🏁 Script executed:

# Check the MedicalRecord entity definition to understand lazy associations
rg -A30 'class MedicalRecord' --type java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 5938


🏁 Script executed:

# Examine the response converter classes
cat src/main/java/org/example/vet1177/dto/response/medicalrecord/MedicalRecordResponse.java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 1805


🏁 Script executed:

# Examine the summary response converter
cat src/main/java/org/example/vet1177/dto/response/medicalrecord/MedicalRecordSummaryResponse.java

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 1024


🏁 Script executed:

# Check the MedicalRecordService to see which repository methods are actually called
rg 'medicalRecordRepository\.' src/main/java/org/example/vet1177/services/MedicalRecordService.java -A2

Repository: ithsjava25/project-backend-org-random-coders

Length of output: 859


findByAssignedVetId and findByStatus are either unused or need @EntityGraph for consistency.

These methods currently have no usages in the codebase, but if they are intended as public API and used with MedicalRecordResponse.from() or MedicalRecordSummaryResponse.from(), they will cause LazyInitializationException when accessing lazy associations (pet, owner, clinic, assignedVet). All other finder methods (findByPetId, findByOwnerId, findByClinicId, findByClinicIdAndStatus) already have @EntityGraph annotations.

Either remove these methods as unused API, or add the appropriate @EntityGraph annotation (e.g., @EntityGraph(attributePaths = {"pet", "owner", "clinic", "assignedVet"})) for consistency with the other finders.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/repository/MedicalRecordRepository.java`
around lines 33 - 34, The repository methods findByAssignedVetId and
findByStatus in MedicalRecordRepository are missing the `@EntityGraph` used by the
other finders and will cause LazyInitializationException when results are mapped
by MedicalRecordResponse.from()/MedicalRecordSummaryResponse.from(); fix by
adding `@EntityGraph`(attributePaths = {"pet","owner","clinic","assignedVet"})
above both findByAssignedVetId(UUID vetId) and findByStatus(RecordStatus status)
to eagerly fetch those associations (or, if these methods are truly unused,
remove them from MedicalRecordRepository to avoid exposing a broken API).

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.example.vet1177.services;

import org.example.vet1177.entities.*;
import org.example.vet1177.exception.BusinessRuleException;
import org.example.vet1177.exception.ResourceNotFoundException;
import org.example.vet1177.repository.MedicalRecordRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -46,7 +48,7 @@ public MedicalRecord create(
@Transactional(readOnly = true)
public MedicalRecord getById(UUID id) {
return medicalRecordRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Ärende hittades inte: " + id));
.orElseThrow(() -> new ResourceNotFoundException("MedicalRecord", id)); // ← rad 49
}

@Transactional(readOnly = true)
Expand All @@ -73,6 +75,11 @@ public List<MedicalRecord> getByClinicAndStatus(UUID clinicId, RecordStatus stat

public MedicalRecord update(UUID id, String title, String description, User updatedBy) {
MedicalRecord record = getById(id);

if (record.getStatus().isFinal()) { // ← mellan rad 75-76
throw new BusinessRuleException("Stängda ärenden kan inte uppdateras");
}

record.setTitle(title);
record.setDescription(description);
record.setUpdatedBy(updatedBy);
Expand Down Expand Up @@ -104,8 +111,8 @@ public MedicalRecord updateStatus(UUID recordId, RecordStatus newStatus, User up
public MedicalRecord close(UUID recordId, User closedBy) {
MedicalRecord record = getById(recordId);

if (record.getStatus() == RecordStatus.CLOSED) {
throw new RuntimeException("Ärendet är redan stängt");
if (record.getStatus().isFinal()) { // ← rad 108
throw new BusinessRuleException("Ärendet är redan stängt");
}

record.setStatus(RecordStatus.CLOSED);
Expand Down