backend DRY/KISS cleanup #324

Merged
RecentRunner merged 14 commits from refactor/backend-cleanup into main 2026-04-18 08:23:37 -06:00
5 changed files with 20 additions and 69 deletions
Showing only changes of commit 9fc51c511d - Show all commits

View File

@@ -2,14 +2,11 @@ package com.petshop.backend.controller;
import com.petshop.backend.dto.pet.PetResponse;
import com.petshop.backend.entity.User;
import com.petshop.backend.security.AppPrincipal;
import com.petshop.backend.service.PetService;
import com.petshop.backend.util.AuthenticationHelper;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -20,8 +17,6 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/pets")
@@ -35,20 +30,20 @@ public class PetImageController {
@PostMapping("/{id}/image")
@PreAuthorize("hasAnyRole('STAFF', 'ADMIN')")
public ResponseEntity<?> uploadPetImage(@PathVariable Long id, @RequestParam("image") MultipartFile image) {
try {
PetResponse response = petService.uploadPetImage(id, image);
return ResponseEntity.ok(response);
} catch (IllegalArgumentException ex) {
return badRequest(ex.getMessage());
} catch (IOException ex) {
return badRequest("Failed to upload pet image: " + ex.getMessage());
}
public ResponseEntity<PetResponse> uploadPetImage(@PathVariable Long id, @RequestParam("image") MultipartFile image) throws IOException {
return ResponseEntity.ok(petService.uploadPetImage(id, image));
}
@GetMapping("/{id}/image")
public ResponseEntity<Resource> getPetImage(@PathVariable Long id) {
PetService.ImagePayload payload = petService.loadPetImage(id, currentUserId(), currentUserRole());
Long userId = null;
User.Role role = null;
try {
userId = AuthenticationHelper.getAuthenticatedUserId();
role = AuthenticationHelper.getAuthenticatedRole();
} catch (Exception ignored) {
}
PetService.ImagePayload payload = petService.loadPetImage(id, userId, role);
return ResponseEntity.ok().contentType(payload.mediaType()).body(payload.resource());
}
@@ -57,34 +52,4 @@ public class PetImageController {
public ResponseEntity<PetResponse> deletePetImage(@PathVariable Long id) {
return ResponseEntity.ok(petService.deletePetImage(id));
}
private ResponseEntity<Map<String, String>> badRequest(String message) {
Map<String, String> error = new HashMap<>();
error.put("message", message);
return ResponseEntity.badRequest().body(error);
}
private Long currentUserId() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return null;
}
Object principal = authentication.getPrincipal();
if (principal instanceof AppPrincipal appPrincipal) {
return appPrincipal.getUserId();
}
return null;
}
private User.Role currentUserRole() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return null;
}
Object principal = authentication.getPrincipal();
if (principal instanceof AppPrincipal appPrincipal) {
return appPrincipal.getRole();
}
return null;
}
}

View File

@@ -15,8 +15,6 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/products")
@@ -30,15 +28,8 @@ public class ProductImageController {
@PostMapping("/{id}/image")
@PreAuthorize("hasAnyRole('STAFF', 'ADMIN')")
public ResponseEntity<?> uploadProductImage(@PathVariable Long id, @RequestParam("image") MultipartFile image) {
try {
ProductResponse response = productService.uploadProductImage(id, image);
return ResponseEntity.ok(response);
} catch (IllegalArgumentException ex) {
return badRequest(ex.getMessage());
} catch (IOException ex) {
return badRequest("Failed to upload product image: " + ex.getMessage());
}
public ResponseEntity<ProductResponse> uploadProductImage(@PathVariable Long id, @RequestParam("image") MultipartFile image) throws IOException {
return ResponseEntity.ok(productService.uploadProductImage(id, image));
}
@GetMapping("/{id}/image")
@@ -52,10 +43,4 @@ public class ProductImageController {
public ResponseEntity<ProductResponse> deleteProductImage(@PathVariable Long id) {
return ResponseEntity.ok(productService.deleteProductImage(id));
}
private ResponseEntity<Map<String, String>> badRequest(String message) {
Map<String, String> error = new HashMap<>();
error.put("message", message);
return ResponseEntity.badRequest().body(error);
}
}

View File

@@ -3,7 +3,6 @@ package com.petshop.backend.controller;
import com.petshop.backend.dto.common.BulkDeleteRequest;
import com.petshop.backend.dto.user.UserRequest;
import com.petshop.backend.dto.user.UserResponse;
import com.petshop.backend.entity.User;
import com.petshop.backend.service.UserService;
import jakarta.validation.Valid;
import org.springframework.data.domain.Page;

View File

@@ -8,6 +8,7 @@ import com.petshop.backend.dto.chat.UpdateConversationRequest;
import com.petshop.backend.entity.Conversation;
import com.petshop.backend.entity.Message;
import com.petshop.backend.entity.User;
import com.petshop.backend.exception.BusinessException;
import com.petshop.backend.exception.ResourceNotFoundException;
import com.petshop.backend.util.ContentFilter;
import com.petshop.backend.repository.ConversationRepository;
@@ -229,7 +230,7 @@ public class ChatService {
return toMessageResponse(message);
} catch (IOException e) {
throw new RuntimeException("Failed to store attachment", e);
throw new BusinessException("Failed to store attachment");
}
}

View File

@@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.petshop.backend.dto.ai.AiChatRequest;
import com.petshop.backend.entity.Pet;
import com.petshop.backend.exception.BusinessException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -52,7 +53,7 @@ public class OpenRouterService {
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("OpenRouter API returned status " + response.statusCode() + ": " + response.body());
throw new BusinessException("OpenRouter API returned status " + response.statusCode() + ": " + response.body());
}
return extractContent(response.body());
@@ -60,10 +61,10 @@ public class OpenRouterService {
catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("AI request was interrupted", e);
throw new BusinessException("AI request was interrupted");
}
catch (Exception e) {
throw new RuntimeException("Failed to call OpenRouter API: " + e.getMessage(), e);
throw new BusinessException("Failed to call OpenRouter API: " + e.getMessage());
}
}
@@ -132,6 +133,6 @@ public class OpenRouterService {
return choices.get(0).path("message").path("content").asText();
}
throw new RuntimeException("No content in OpenRouter response: " + responseBody);
throw new BusinessException("No content in OpenRouter response");
}
}