Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public List<ActivityLogResponse> getLogsByRecord(
@PathVariable UUID recordId,
@RequestHeader("userId") UUID userId
) {
User user = userService.getById(userId);
User user = userService.getUserEntityById(userId);

return activityLogService.getByRecord(recordId, user)
.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public ResponseEntity<MedicalRecordResponse> assignVet(
@AuthenticationPrincipal User currentUser) {

MedicalRecord record = medicalRecordService.getById(id);
User vetToAssign = userService.getById(request.vetId());
User vetToAssign = userService.getUserEntityById(request.vetId());
medicalRecordPolicy.canAssignVet(currentUser, record, vetToAssign);

return ResponseEntity.ok(
Expand Down
60 changes: 60 additions & 0 deletions src/main/java/org/example/vet1177/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package org.example.vet1177.controller;

import jakarta.validation.Valid;
import org.example.vet1177.dto.request.user.UserRequest;
import org.example.vet1177.dto.response.user.UserResponse;
import org.example.vet1177.services.UserService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.example.vet1177.dto.request.user.UserUpdateRequest;

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

@RestController
@RequestMapping("/api/users")
public class UserController {
Comment thread
coderabbitai[bot] marked this conversation as resolved.

private final UserService userService;

public UserController(UserService userService) {
this.userService = userService;
}

//GET /users- Hämta alla användare
@GetMapping
public ResponseEntity<List<UserResponse>> getAllUsers() {
List<UserResponse> users = userService.getAllUsers();
return ResponseEntity.ok(users);
}

// GET /users/{id}- Hämta 1 användare
@GetMapping("/{id}")
public ResponseEntity<UserResponse> getUserById(@PathVariable UUID id) {
UserResponse user = userService.getById(id);
return ResponseEntity.ok(user);
}

//POST /users - skapa ny användare
@PostMapping
public ResponseEntity<UserResponse> createUser(@Valid @RequestBody UserRequest request) {
UserResponse user = userService.createUser(request);
return ResponseEntity.status(HttpStatus.CREATED).body(user);
}

//PUT /users/{id} - uppdatera användare
@PutMapping("/{id}")
public ResponseEntity<UserResponse> updateUser(@PathVariable UUID id,
@Valid @RequestBody UserUpdateRequest request) {
UserResponse user = userService.updateUser(id, request);
return ResponseEntity.ok(user);
}
Comment on lines +40 to +52

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
# Verify GlobalExceptionHandler doesn't handle IllegalArgumentException
rg -n "IllegalArgumentException" --type=java src/main/java/org/example/vet1177/exception/

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

Length of output: 70


🏁 Script executed:

fd -t f "GlobalExceptionHandler" src/main/java/

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

Length of output: 159


🏁 Script executed:

cat -n src/main/java/org/example/vet1177/exception/GlobalExceptionHandler.java

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

Length of output: 3164


🏁 Script executed:

rg -n "IllegalArgumentException" --type=java src/main/java/ -A 3 -B 1

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

Length of output: 6319


🏁 Script executed:

rg -n "throw new IllegalArgumentException" --type=java src/main/java/

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

Length of output: 1996


IllegalArgumentException from UserService will return HTTP 500 instead of appropriate 4xx responses.

The GlobalExceptionHandler does not have an @ExceptionHandler(IllegalArgumentException.class) method. When UserService throws IllegalArgumentException for email uniqueness violations (lines 111, 117 in UserService) or clinic requirement violations (line 124), these exceptions fall through to the generic Exception handler, returning HTTP 500 with "Something went wrong" instead of a meaningful response like 400 Bad Request or 409 Conflict.

Consider either:

  1. Adding an @ExceptionHandler(IllegalArgumentException.class) in GlobalExceptionHandler, or
  2. Changing the service to throw BusinessRuleException (already handled as 400 Bad Request) or a custom DuplicateEmailException
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/org/example/vet1177/controller/UserController.java` around
lines 40 - 53, UserService's createUser/updateUser currently throw
IllegalArgumentException for email-uniqueness and clinic rules which bubbles to
the generic exception handler and returns 500; add a dedicated handler in
GlobalExceptionHandler (an `@ExceptionHandler`(IllegalArgumentException.class)
method) that maps these IllegalArgumentException cases to an appropriate 4xx
response (e.g., return ResponseEntity.status(HttpStatus.CONFLICT) for
duplicate-email messages or HttpStatus.BAD_REQUEST for clinic rule violations)
and include the exception message in the response body, or alternatively modify
UserService to throw an existing BusinessRuleException or a new
DuplicateEmailException instead of IllegalArgumentException so the exception is
already handled correctly.


//DELETE /users/{id} - Tar bort användare
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable UUID id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package org.example.vet1177.dto.request.user;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import org.example.vet1177.entities.Role;

import java.util.UUID;

public class UserRequest {

@NotBlank
@Size(min = 2, max = 100)
private String name;

@NotBlank
@Email
private String email;

@NotBlank
@Size(min = 8, max = 100)
private String password;

@NotNull
private Role role;

private UUID clinicId;

public UserRequest(){
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public Role getRole() {
return role;
}

public void setRole(Role role) {
this.role = role;
}

public UUID getClinicId() {
return clinicId;
}

public void setClinicId(UUID clinicId) {
this.clinicId = clinicId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.example.vet1177.dto.request.user;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.Size;

import java.util.UUID;

public class UserUpdateRequest {

@Size(min = 2, max = 100)
private String name;

@Email
private String email;

private UUID clinicId;

public UUID getClinicId() {
return clinicId;
}

public void setClinicId(UUID clinicId) {
this.clinicId = clinicId;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.example.vet1177.dto.response.user;

import org.example.vet1177.entities.Role;

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

public class UserResponse {

private UUID id;
private String name;
private String email;
private Role role;
private UUID clinicId;
private Instant createdAt;
private Instant updatedAt;

public UserResponse() {
}

public UserResponse(UUID id, String name, String email, Role role, UUID clinicId, Instant createdAt, Instant updatedAt) {
this.id =id;
this.name =name;
this.email = email;
this.role = role;
this.clinicId = clinicId;
this.createdAt = createdAt;
this.updatedAt =updatedAt;
}

public UUID getId() {
return id;
}

public void setId(UUID id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public Role getRole() {
return role;
}

public void setRole(Role role) {
this.role = role;
}

public UUID getClinicId() {
return clinicId;
}

public void setClinicId(UUID clinicId) {
this.clinicId = clinicId;
}

public Instant getCreatedAt() {
return createdAt;
}

public void setCreatedAt(Instant createdAt) {
this.createdAt = createdAt;
}

public Instant getUpdatedAt() {
return updatedAt;
}

public void setUpdatedAt(Instant updatedAt) {
this.updatedAt = updatedAt;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ public interface MedicalRecordRepository extends JpaRepository<MedicalRecord, UU
List<MedicalRecord> findByAssignedVetId(UUID vetId);
List<MedicalRecord> findByStatus(RecordStatus status);
boolean existsByPetIdAndClinicId(UUID petId, UUID clinicId);
boolean existsByOwnerId(UUID ownerId);
boolean existsByAssignedVetId(UUID vetId);
boolean existsByCreatedById(UUID userId);
boolean existsByUpdatedById(UUID userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ public interface PetRepository extends JpaRepository<Pet, UUID> {

//hämta ett specifikt pet för en specifik owner
Optional<Pet> findByIdAndOwnerId(UUID petId, UUID ownerId);

boolean existsByOwner_Id(UUID ownerId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
public interface UserRepository extends JpaRepository <User, UUID> {

Optional<User> findByEmail(String email);
boolean existsByEmail(String email);
boolean existsByEmailAndIdNot(String email, UUID id);
}
Loading