diff --git a/backend/src/main/java/com/petshop/backend/controller/AdoptionController.java b/backend/src/main/java/com/petshop/backend/controller/AdoptionController.java index 84005778..1be65273 100644 --- a/backend/src/main/java/com/petshop/backend/controller/AdoptionController.java +++ b/backend/src/main/java/com/petshop/backend/controller/AdoptionController.java @@ -4,8 +4,6 @@ import com.petshop.backend.dto.adoption.AdoptionRequest; import com.petshop.backend.dto.adoption.AdoptionResponse; import com.petshop.backend.dto.adoption.CustomerAdoptionRequest; import com.petshop.backend.dto.common.BulkDeleteRequest; -import com.petshop.backend.entity.User; -import com.petshop.backend.repository.UserRepository; import com.petshop.backend.service.AdoptionService; import com.petshop.backend.util.AuthenticationHelper; import jakarta.validation.Valid; @@ -23,11 +21,11 @@ import java.time.LocalDate; public class AdoptionController { private final AdoptionService adoptionService; - private final UserRepository userRepository; + private final AuthenticationHelper authHelper; - public AdoptionController(AdoptionService adoptionService, UserRepository userRepository) { + public AdoptionController(AdoptionService adoptionService, AuthenticationHelper authHelper) { this.adoptionService = adoptionService; - this.userRepository = userRepository; + this.authHelper = authHelper; } @GetMapping @@ -40,9 +38,7 @@ public class AdoptionController { @RequestParam(required = false) String date, Pageable pageable) { - Long effectiveCustomerId = AuthenticationHelper.isCustomer() - ? AuthenticationHelper.getAuthenticatedUser(userRepository).getId() - : customerId; + Long effectiveCustomerId = authHelper.getEffectiveCustomerId(customerId); LocalDate adoptionDate = (date != null && !date.isBlank()) ? LocalDate.parse(date) : null; @@ -52,7 +48,7 @@ public class AdoptionController { @GetMapping("/{id}") @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity getAdoptionById(@PathVariable Long id) { - Long customerId = AuthenticationHelper.getCustomerIdOrNull(userRepository); + Long customerId = authHelper.getCustomerIdOrNull(); return ResponseEntity.ok(adoptionService.getAdoptionById(id, customerId)); } @@ -65,16 +61,15 @@ public class AdoptionController { @PostMapping("/request") @PreAuthorize("hasAnyRole('CUSTOMER', 'ADMIN')") public ResponseEntity requestAdoption(@Valid @RequestBody CustomerAdoptionRequest request) { - User user = AuthenticationHelper.getAuthenticatedUser(userRepository); return ResponseEntity.status(HttpStatus.CREATED).body( - adoptionService.requestAdoption(user.getId(), request.getPetId(), request.getEmployeeId(), request.getSourceStoreId(), request.getAdoptionDate()) + adoptionService.requestAdoption(authHelper.getAuthenticatedUser().getId(), request.getPetId(), request.getEmployeeId(), request.getSourceStoreId(), request.getAdoptionDate()) ); } @PatchMapping("/{id}/cancel") @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity cancelAdoption(@PathVariable Long id) { - Long customerId = AuthenticationHelper.getCustomerIdOrNull(userRepository); + Long customerId = authHelper.getCustomerIdOrNull(); return ResponseEntity.ok(adoptionService.cancelAdoption(id, customerId)); } diff --git a/backend/src/main/java/com/petshop/backend/controller/AiChatController.java b/backend/src/main/java/com/petshop/backend/controller/AiChatController.java index f65dbaf0..6ed746a7 100644 --- a/backend/src/main/java/com/petshop/backend/controller/AiChatController.java +++ b/backend/src/main/java/com/petshop/backend/controller/AiChatController.java @@ -4,15 +4,14 @@ import com.petshop.backend.dto.ai.AiChatRequest; import com.petshop.backend.dto.ai.AiChatResponse; import com.petshop.backend.entity.Pet; import com.petshop.backend.entity.User; +import com.petshop.backend.exception.BusinessException; import com.petshop.backend.repository.PetRepository; -import com.petshop.backend.repository.UserRepository; import com.petshop.backend.service.OpenRouterService; import com.petshop.backend.util.AuthenticationHelper; import com.petshop.backend.util.ContentFilter; import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.web.bind.annotation.*; import java.util.Collections; @@ -24,43 +23,31 @@ public class AiChatController { private final OpenRouterService openRouterService; private final PetRepository petRepository; - private final UserRepository userRepository; + private final AuthenticationHelper authHelper; public AiChatController(OpenRouterService openRouterService, PetRepository petRepository, - UserRepository userRepository) { + AuthenticationHelper authHelper) { this.openRouterService = openRouterService; this.petRepository = petRepository; - this.userRepository = userRepository; - } - - private User getCurrentUser() { - try { - return AuthenticationHelper.getAuthenticatedUser(userRepository); - } - - catch (RuntimeException ex) { - throw new UsernameNotFoundException(ex.getMessage(), ex); - } + this.authHelper = authHelper; } @PostMapping("/message") @PreAuthorize("isAuthenticated()") public ResponseEntity sendMessage(@Valid @RequestBody AiChatRequest request) { if (request.getMessage() == null || request.getMessage().isBlank()) { - return ResponseEntity.badRequest().body(AiChatResponse.fail("Message cannot be empty")); + throw new BusinessException("Message cannot be empty"); } ContentFilter.validate(request.getMessage()); - User user = getCurrentUser(); + User user = authHelper.getAuthenticatedUser(); List userPets; try { userPets = petRepository.findAllByOwner_IdAndPetStatusInOrderByPetNameAsc( user.getId(), List.of("Adopted", "Owned")); - } - - catch (Exception e) { + } catch (Exception e) { userPets = Collections.emptyList(); } @@ -72,15 +59,9 @@ public class AiChatController { ); return ResponseEntity.ok(AiChatResponse.ok(aiReply)); - } - - catch (IllegalStateException e) { - + } catch (IllegalStateException e) { return ResponseEntity.status(503).body(AiChatResponse.fail("AI service is not configured. Please contact support.")); - } - - catch (Exception e) { - + } catch (Exception e) { return ResponseEntity.status(502).body(AiChatResponse.fail("AI service is temporarily unavailable. Please try again later.")); } } diff --git a/backend/src/main/java/com/petshop/backend/controller/AnalyticsController.java b/backend/src/main/java/com/petshop/backend/controller/AnalyticsController.java index fedf5a16..08aea44d 100644 --- a/backend/src/main/java/com/petshop/backend/controller/AnalyticsController.java +++ b/backend/src/main/java/com/petshop/backend/controller/AnalyticsController.java @@ -1,8 +1,6 @@ package com.petshop.backend.controller; import com.petshop.backend.dto.analytics.DashboardResponse; -import com.petshop.backend.entity.User; -import com.petshop.backend.repository.UserRepository; import com.petshop.backend.service.AnalyticsService; import com.petshop.backend.util.AuthenticationHelper; import org.springframework.format.annotation.DateTimeFormat; @@ -20,11 +18,11 @@ import java.time.LocalDate; public class AnalyticsController { private final AnalyticsService analyticsService; - private final UserRepository userRepository; + private final AuthenticationHelper authHelper; - public AnalyticsController(AnalyticsService analyticsService, UserRepository userRepository) { + public AnalyticsController(AnalyticsService analyticsService, AuthenticationHelper authHelper) { this.analyticsService = analyticsService; - this.userRepository = userRepository; + this.authHelper = authHelper; } @GetMapping("/dashboard") @@ -41,7 +39,7 @@ public class AnalyticsController { if (top < 1 || top > 50) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "top must be between 1 and 50"); } - User user = AuthenticationHelper.getAuthenticatedUser(userRepository); + var user = authHelper.getAuthenticatedUser(); java.time.LocalDateTime endDateTime = endDate != null ? endDate.plusDays(1).atStartOfDay() : null; return ResponseEntity.ok(analyticsService.getDashboardData(days, top, user, paymentMethod, storeId, channel, endDateTime)); } diff --git a/backend/src/main/java/com/petshop/backend/controller/AppointmentController.java b/backend/src/main/java/com/petshop/backend/controller/AppointmentController.java index 364f836e..301b4a77 100644 --- a/backend/src/main/java/com/petshop/backend/controller/AppointmentController.java +++ b/backend/src/main/java/com/petshop/backend/controller/AppointmentController.java @@ -3,8 +3,6 @@ package com.petshop.backend.controller; import com.petshop.backend.dto.appointment.AppointmentRequest; import com.petshop.backend.dto.appointment.AppointmentResponse; import com.petshop.backend.dto.common.BulkDeleteRequest; -import com.petshop.backend.entity.User; -import com.petshop.backend.repository.UserRepository; import com.petshop.backend.service.AppointmentService; import com.petshop.backend.util.AuthenticationHelper; import jakarta.validation.Valid; @@ -23,11 +21,11 @@ import java.util.List; public class AppointmentController { private final AppointmentService appointmentService; - private final UserRepository userRepository; + private final AuthenticationHelper authHelper; - public AppointmentController(AppointmentService appointmentService, UserRepository userRepository) { + public AppointmentController(AppointmentService appointmentService, AuthenticationHelper authHelper) { this.appointmentService = appointmentService; - this.userRepository = userRepository; + this.authHelper = authHelper; } @GetMapping @@ -41,9 +39,7 @@ public class AppointmentController { @RequestParam(required = false) Long employeeId, Pageable pageable) { - Long effectiveCustomerId = AuthenticationHelper.isCustomer() - ? AuthenticationHelper.getAuthenticatedUser(userRepository).getId() - : customerId; + Long effectiveCustomerId = authHelper.getEffectiveCustomerId(customerId); LocalDate appointmentDate = (date != null && !date.isBlank()) ? LocalDate.parse(date) : null; @@ -54,7 +50,7 @@ public class AppointmentController { @GetMapping("/{id}") @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity getAppointmentById(@PathVariable Long id) { - Long customerId = AuthenticationHelper.getCustomerIdOrNull(userRepository); + Long customerId = authHelper.getCustomerIdOrNull(); return ResponseEntity.ok(appointmentService.getAppointmentById(id, customerId)); } @@ -62,8 +58,7 @@ public class AppointmentController { @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity createAppointment(@Valid @RequestBody AppointmentRequest request) { if (AuthenticationHelper.isCustomer()) { - User user = AuthenticationHelper.getAuthenticatedUser(userRepository); - if (!request.getCustomerId().equals(user.getId())) { + if (!request.getCustomerId().equals(authHelper.getAuthenticatedUser().getId())) { throw new org.springframework.security.access.AccessDeniedException("You can only create appointments for yourself"); } } @@ -74,7 +69,7 @@ public class AppointmentController { @PatchMapping("/{id}/cancel") @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity cancelAppointment(@PathVariable Long id) { - Long customerId = AuthenticationHelper.getCustomerIdOrNull(userRepository); + Long customerId = authHelper.getCustomerIdOrNull(); return ResponseEntity.ok(appointmentService.cancelAppointment(id, customerId)); } diff --git a/backend/src/main/java/com/petshop/backend/controller/AuthController.java b/backend/src/main/java/com/petshop/backend/controller/AuthController.java index b0b1ffa5..b366bd02 100644 --- a/backend/src/main/java/com/petshop/backend/controller/AuthController.java +++ b/backend/src/main/java/com/petshop/backend/controller/AuthController.java @@ -64,8 +64,9 @@ public class AuthController { private final PasswordResetService passwordResetService; private final EmailService emailService; private final UserAuthCacheService userAuthCacheService; + private final AuthenticationHelper authHelper; - public AuthController(AuthenticationManager authenticationManager, UserRepository userRepository, JwtUtil jwtUtil, PasswordEncoder passwordEncoder, AvatarStorageService avatarStorageService, ActivityLogService activityLogService, PasswordResetService passwordResetService, EmailService emailService, UserAuthCacheService userAuthCacheService) { + public AuthController(AuthenticationManager authenticationManager, UserRepository userRepository, JwtUtil jwtUtil, PasswordEncoder passwordEncoder, AvatarStorageService avatarStorageService, ActivityLogService activityLogService, PasswordResetService passwordResetService, EmailService emailService, UserAuthCacheService userAuthCacheService, AuthenticationHelper authHelper) { this.authenticationManager = authenticationManager; this.userRepository = userRepository; this.jwtUtil = jwtUtil; @@ -75,6 +76,7 @@ public class AuthController { this.passwordResetService = passwordResetService; this.emailService = emailService; this.userAuthCacheService = userAuthCacheService; + this.authHelper = authHelper; } @PostMapping("/register") @@ -180,7 +182,7 @@ public class AuthController { @Transactional(readOnly = true) @GetMapping("/me") public ResponseEntity getCurrentUser() { - User user = getAuthenticatedUser(); + User user = authHelper.getAuthenticatedUser(); return ResponseEntity.ok(toUserInfoResponse(user)); } @@ -278,7 +280,7 @@ public class AuthController { @PostMapping("/me/avatar") public ResponseEntity uploadAvatar(@RequestParam("avatar") MultipartFile file) { - User user = getAuthenticatedUser(); + User user = authHelper.getAuthenticatedUser(); ImageValidationUtil.validate(file); @@ -297,7 +299,7 @@ public class AuthController { @GetMapping("/me/avatar") public ResponseEntity getAvatar() { - User user = getAuthenticatedUser(); + User user = authHelper.getAuthenticatedUser(); if (!avatarStorageService.hasAvatar(user)) { throw new ResourceNotFoundException("No avatar uploaded"); @@ -310,7 +312,7 @@ public class AuthController { @GetMapping("/me/avatar/file") public ResponseEntity getAvatarFile() { - User user = getAuthenticatedUser(); + User user = authHelper.getAuthenticatedUser(); if (!avatarStorageService.hasAvatar(user)) { return ResponseEntity.notFound().build(); @@ -327,7 +329,7 @@ public class AuthController { @DeleteMapping("/me/avatar") public ResponseEntity deleteAvatar() { - User user = getAuthenticatedUser(); + User user = authHelper.getAuthenticatedUser(); if (avatarStorageService.hasAvatar(user)) { try { @@ -352,11 +354,4 @@ public class AuthController { return ResponseEntity.ok(response); } - private User getAuthenticatedUser() { - try { - return AuthenticationHelper.getAuthenticatedUser(userRepository); - } catch (RuntimeException ex) { - throw new UsernameNotFoundException(ex.getMessage(), ex); - } - } } diff --git a/backend/src/main/java/com/petshop/backend/controller/ChatController.java b/backend/src/main/java/com/petshop/backend/controller/ChatController.java index 94fb229a..f1e26209 100644 --- a/backend/src/main/java/com/petshop/backend/controller/ChatController.java +++ b/backend/src/main/java/com/petshop/backend/controller/ChatController.java @@ -9,7 +9,6 @@ import com.petshop.backend.entity.Message; import com.petshop.backend.entity.User; import com.petshop.backend.exception.ResourceNotFoundException; import com.petshop.backend.repository.MessageRepository; -import com.petshop.backend.repository.UserRepository; import com.petshop.backend.service.ChatAttachmentStorageService; import com.petshop.backend.service.ChatRealtimeService; import com.petshop.backend.service.ChatService; @@ -22,7 +21,6 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -35,33 +33,25 @@ public class ChatController { private final ChatService chatService; private final ChatRealtimeService chatRealtimeService; private final OpenRouterAiService openRouterAiService; - private final UserRepository userRepository; + private final AuthenticationHelper authHelper; private final ChatAttachmentStorageService attachmentStorageService; private final MessageRepository messageRepository; - public ChatController(ChatService chatService, ChatRealtimeService chatRealtimeService, - OpenRouterAiService openRouterAiService, UserRepository userRepository, ChatAttachmentStorageService attachmentStorageService, + public ChatController(ChatService chatService, ChatRealtimeService chatRealtimeService, + OpenRouterAiService openRouterAiService, AuthenticationHelper authHelper, ChatAttachmentStorageService attachmentStorageService, MessageRepository messageRepository) { this.chatService = chatService; this.chatRealtimeService = chatRealtimeService; this.openRouterAiService = openRouterAiService; - this.userRepository = userRepository; + this.authHelper = authHelper; this.attachmentStorageService = attachmentStorageService; this.messageRepository = messageRepository; } - private User getCurrentUser() { - try { - return AuthenticationHelper.getAuthenticatedUser(userRepository); - } catch (RuntimeException ex) { - throw new UsernameNotFoundException(ex.getMessage(), ex); - } - } - @PostMapping("/conversations") @PreAuthorize("isAuthenticated()") public ResponseEntity createConversation(@Valid @RequestBody ConversationRequest request) { - User user = getCurrentUser(); + User user = authHelper.getAuthenticatedUser(); ConversationResponse response = chatService.createConversation(user.getId(), request); chatRealtimeService.publishNewConversation(response); return ResponseEntity.status(HttpStatus.CREATED).body(response); @@ -71,7 +61,7 @@ public class ChatController { @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity> getConversations( @RequestParam(required = false, defaultValue = "false") boolean mine) { - User user = getCurrentUser(); + User user = authHelper.getAuthenticatedUser(); List conversations = chatService.getConversations(user.getId(), user.getRole(), mine); return ResponseEntity.ok(conversations); } @@ -79,7 +69,7 @@ public class ChatController { @GetMapping("/conversations/{id}") @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity getConversation(@PathVariable Long id) { - User user = getCurrentUser(); + User user = authHelper.getAuthenticatedUser(); ConversationResponse conversation = chatService.getConversation(id, user.getId(), user.getRole()); return ResponseEntity.ok(conversation); } @@ -89,7 +79,7 @@ public class ChatController { public ResponseEntity sendMessage( @PathVariable Long id, @Valid @RequestBody MessageRequest request) { - User user = getCurrentUser(); + User user = authHelper.getAuthenticatedUser(); MessageResponse message = chatService.sendMessage(id, user.getId(), user.getRole(), request); chatRealtimeService.publishMessage(id, message); chatRealtimeService.publishConversationUpdate(id); @@ -103,7 +93,7 @@ public class ChatController { @PathVariable Long id, @RequestParam("file") MultipartFile file, @RequestParam(value = "content", required = false) String content) { - User user = getCurrentUser(); + User user = authHelper.getAuthenticatedUser(); MessageResponse message = chatService.sendMessageWithAttachment(id, user.getId(), user.getRole(), file, content); chatRealtimeService.publishMessage(id, message); chatRealtimeService.publishConversationUpdate(id); @@ -114,7 +104,7 @@ public class ChatController { @GetMapping("/messages/{messageId}/attachment") @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity getMessageAttachment(@PathVariable Long messageId) { - User user = getCurrentUser(); + User user = authHelper.getAuthenticatedUser(); Message message = messageRepository.findById(messageId) .orElseThrow(() -> new ResourceNotFoundException("Message not found with id: " + messageId)); @@ -140,7 +130,7 @@ public class ChatController { @GetMapping("/conversations/{id}/messages") @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity> getMessages(@PathVariable Long id) { - User user = getCurrentUser(); + User user = authHelper.getAuthenticatedUser(); List messages = chatService.getMessages(id, user.getId(), user.getRole()); return ResponseEntity.ok(messages); } @@ -148,7 +138,7 @@ public class ChatController { @PostMapping("/conversations/{id}/request-human") @PreAuthorize("isAuthenticated()") public ResponseEntity requestHumanTakeover(@PathVariable Long id) { - User user = getCurrentUser(); + User user = authHelper.getAuthenticatedUser(); ConversationResponse conversation = chatService.requestHumanTakeover(id, user.getId(), user.getRole()); chatRealtimeService.publishConversationUpdate(id); return ResponseEntity.ok(conversation); @@ -157,7 +147,7 @@ public class ChatController { @PutMapping("/conversations/{id}") @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity updateConversation(@PathVariable Long id, @Valid @RequestBody UpdateConversationRequest request) { - User user = getCurrentUser(); + User user = authHelper.getAuthenticatedUser(); ConversationResponse conversation = chatService.updateConversation(id, user.getId(), user.getRole(), request); chatRealtimeService.publishConversationUpdate(id); return ResponseEntity.ok(conversation); diff --git a/backend/src/main/java/com/petshop/backend/controller/RefundController.java b/backend/src/main/java/com/petshop/backend/controller/RefundController.java index da58c6a0..b8e20241 100644 --- a/backend/src/main/java/com/petshop/backend/controller/RefundController.java +++ b/backend/src/main/java/com/petshop/backend/controller/RefundController.java @@ -3,7 +3,6 @@ package com.petshop.backend.controller; import com.petshop.backend.dto.refund.RefundRequest; import com.petshop.backend.dto.refund.RefundResponse; import com.petshop.backend.dto.refund.RefundUpdateRequest; -import com.petshop.backend.repository.UserRepository; import com.petshop.backend.service.RefundService; import com.petshop.backend.util.AuthenticationHelper; import jakarta.validation.Valid; @@ -19,24 +18,24 @@ import java.util.List; public class RefundController { private final RefundService refundService; - private final UserRepository userRepository; + private final AuthenticationHelper authHelper; - public RefundController(RefundService refundService, UserRepository userRepository) { + public RefundController(RefundService refundService, AuthenticationHelper authHelper) { this.refundService = refundService; - this.userRepository = userRepository; + this.authHelper = authHelper; } @PostMapping @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF')") public ResponseEntity createRefund(@Valid @RequestBody RefundRequest request) { - Long customerId = AuthenticationHelper.getCustomerIdOrNull(userRepository); + Long customerId = authHelper.getCustomerIdOrNull(); return ResponseEntity.status(HttpStatus.CREATED).body(refundService.createRefund(request, customerId)); } @GetMapping @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity> getAllRefunds() { - Long customerId = AuthenticationHelper.getCustomerIdOrNull(userRepository); + Long customerId = authHelper.getCustomerIdOrNull(); List refunds = refundService.getAllRefunds(customerId); return ResponseEntity.ok(refunds); } @@ -44,7 +43,7 @@ public class RefundController { @GetMapping("/{id}") @PreAuthorize("hasAnyRole('CUSTOMER', 'STAFF', 'ADMIN')") public ResponseEntity getRefundById(@PathVariable Long id) { - Long customerId = AuthenticationHelper.getCustomerIdOrNull(userRepository); + Long customerId = authHelper.getCustomerIdOrNull(); return ResponseEntity.ok(refundService.getRefundById(id, customerId)); }