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
78 changes: 68 additions & 10 deletions src/main/java/org/example/vet1177/controller/PetController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,28 @@
import org.example.vet1177.dto.request.pet.PetRequest;
import org.example.vet1177.dto.response.pet.PetResponse;
import org.example.vet1177.entities.Pet;
import org.example.vet1177.entities.User;
import org.example.vet1177.services.PetService;
import org.example.vet1177.services.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/pets")
public class PetController {

private final PetService petService;
private final UserService userService;

public PetController(PetService petService) {
public PetController(PetService petService, UserService userService) {
this.petService = petService;
this.userService = userService;
}

//POST / pets - skapa nytt djur
@PostMapping
public PetResponse createPet(
// TODO: Ersätt med användare från autentiserad kontext (t.ex. JWT / Spring Security)
Expand All @@ -27,17 +34,68 @@ public PetResponse createPet(
@Valid @RequestBody PetRequest request
) {
Pet saved = petService.createPet(currentUserId, ownerId, request);
return toResponse(saved);
}

// GET / pets/{petId} - hämta ett specifikt djur
@GetMapping("/{petId}")
public ResponseEntity<PetResponse> getPetById(
@RequestHeader UUID currentUserId,
@PathVariable UUID petId
) {
User currentUser = userService.getUserEntityById(currentUserId);
Pet pet = petService.getPetById(petId, currentUser);
return ResponseEntity.ok(toResponse(pet));
}

// GET/pets/owner/{ownerId} - hämta alla djur för en ägare
@GetMapping("/owner/{ownerId}")
public ResponseEntity<List<PetResponse>> getPetsByOwner(
@RequestHeader UUID currentUserId,
@PathVariable UUID ownerId
) {
List<PetResponse> pets = petService.getPetsByOwner(currentUserId, ownerId)
.stream()
.map(this::toResponse)
.toList();
return ResponseEntity.ok(pets);
}

// PUT /pets/{petId} - uppdatera ett djur
@PutMapping("/{petId}")
public ResponseEntity<PetResponse> updatePet(
@RequestHeader UUID currentUserId,
@PathVariable UUID petId,
@Valid @RequestBody PetRequest request
) {
Pet updated = petService.updatePet(currentUserId, petId, request);
return ResponseEntity.ok(toResponse(updated));
}

// DELETE /pets/{petId} - radera ett djur
@DeleteMapping("/{petId}")
public ResponseEntity<Void> deletePet(
@RequestHeader UUID currentUserId,
@PathVariable UUID petId
) {
User currentUser = userService.getUserEntityById(currentUserId);
petService.deletePet(petId, currentUser);
return ResponseEntity.noContent().build();
}

//Helper
private PetResponse toResponse(Pet pet) {
return new PetResponse(
saved.getId(),
saved.getOwner().getId(),
saved.getName(),
saved.getSpecies(),
saved.getBreed(),
saved.getDateOfBirth(),
saved.getWeightKg(),
saved.getCreatedAt(),
saved.getUpdatedAt()
pet.getId(),
pet.getOwner().getId(),
pet.getName(),
pet.getSpecies(),
pet.getBreed(),
pet.getDateOfBirth(),
pet.getWeightKg(),
pet.getCreatedAt(),
pet.getUpdatedAt()
);
}

}
30 changes: 16 additions & 14 deletions src/main/java/org/example/vet1177/services/PetService.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
import org.example.vet1177.entities.Pet;
import org.example.vet1177.entities.Role;
import org.example.vet1177.entities.User;
import org.example.vet1177.exception.BusinessRuleException;
import org.example.vet1177.exception.ForbiddenException;
import org.example.vet1177.exception.ResourceNotFoundException;
import org.example.vet1177.policy.PetPolicy;
import org.example.vet1177.repository.MedicalRecordRepository;
import org.example.vet1177.repository.PetRepository;
Expand Down Expand Up @@ -40,18 +43,17 @@ public Pet createPet(UUID currentUserId, UUID ownerId, PetRequest request) {
User currentUser = getUserById(currentUserId);

if (!petPolicy.canCreate(currentUser)) {
throw new RuntimeException("Du kan inte lägga till ett djur");
throw new ForbiddenException("Du kan inte lägga till ett djur");
}

User owner;

if (currentUser.getRole() == Role.ADMIN) {
if (ownerId == null) {
throw new RuntimeException("Admin måste ange ownerId");
throw new BusinessRuleException("Admin måste ange ownerId");
}
owner = getUserById(ownerId);
if (owner.getRole() != Role.OWNER) {
throw new RuntimeException("ownerId måste tillhöra en användare med rollen OWNER");
throw new BusinessRuleException("ownerId måste tillhöra en användare med rollen OWNER");
}
} else {
owner = currentUser;
Expand All @@ -68,15 +70,15 @@ public Pet createPet(UUID currentUserId, UUID ownerId, PetRequest request) {
// - Måste vara ADMIN eller OWNER för att se pet
public Pet getPetById(UUID petId, User currentUser) {
Pet pet = petRepository.findById(petId)
.orElseThrow(() -> new RuntimeException("Pet not found"));
.orElseThrow(() -> new ResourceNotFoundException("Pet", petId));

if (petPolicy.canView(currentUser, pet)) {
return pet;
}

if (currentUser.getRole() == Role.VET) {
if (currentUser.getClinic() == null) {
throw new RuntimeException("Veterinären saknar koppling till klinik");
throw new ForbiddenException("Veterinären saknar koppling till klinik");
}
boolean vetHasAccess = medicalRecordRepository
.existsByPetIdAndClinicId(petId, currentUser.getClinic().getId());
Expand All @@ -86,14 +88,14 @@ public Pet getPetById(UUID petId, User currentUser) {
}
}

throw new RuntimeException("Du har inte behörighet att se detta djur");
throw new ForbiddenException("Du har inte behörighet att se detta djur");
}

// Lista djur som tillhör ägaren
public List<Pet> getPetsByOwner(UUID currentUserId, UUID ownerId) {
User currentUser = getUserById(currentUserId);
if (!petPolicy.canViewOwnerPets(currentUser, ownerId)){
throw new RuntimeException("Du saknar behörighet");
throw new ForbiddenException("Du saknar behörighet");
}
return petRepository.findByOwnerId(ownerId);
}
Expand All @@ -104,7 +106,7 @@ public Pet updatePet(UUID currentUserId, UUID petId, PetRequest request) {
Pet existingPet = getPetByIdOrThrow(petId);

if (!petPolicy.canUpdate(currentUser, existingPet)) {
throw new RuntimeException("Du saknar behörighet för att uppdatera info om djuret");
throw new ForbiddenException("Du saknar behörighet för att uppdatera info om djuret");
}

existingPet.setName(request.getName());
Expand All @@ -121,16 +123,16 @@ public Pet updatePet(UUID currentUserId, UUID petId, PetRequest request) {
@Transactional
public void deletePet(UUID petId, User currentUser) {
Pet pet = petRepository.findById(petId)
.orElseThrow(() -> new RuntimeException("Djuret finns inte"));
.orElseThrow(() -> new ResourceNotFoundException("Pet", petId));

if (!petPolicy.canDelete(currentUser, pet)) {
throw new RuntimeException("Du har inte behörighet att radera detta djur");
throw new ForbiddenException("Du har inte behörighet att radera detta djur");
}
try {
petRepository.delete(pet);
petRepository.flush();
} catch (DataIntegrityViolationException e) {
throw new RuntimeException("Djuret kan inte raderas eftersom journaler finns kopplade");
throw new BusinessRuleException("Djuret kan inte raderas eftersom journaler finns kopplade");
}
}

Expand All @@ -139,11 +141,11 @@ public void deletePet(UUID petId, User currentUser) {
//HELPERS
private User getUserById(UUID userId) {
return userRepository.findById(userId)
.orElseThrow(()-> new RuntimeException("Användare ej hittad"));
.orElseThrow(()-> new ResourceNotFoundException("User", userId));
}
private Pet getPetByIdOrThrow(UUID petId) {
return petRepository.findById(petId)
.orElseThrow(() -> new RuntimeException("Djuret ej hittat"));
.orElseThrow(() -> new ResourceNotFoundException("Pet", petId));
}

private void applyPetRequest(Pet target, PetRequest request) {
Expand Down