fix validation bugs

This commit is contained in:
2026-04-19 18:26:16 -06:00
parent 2bbb722693
commit ca87b2578c
7 changed files with 58 additions and 25 deletions

View File

@@ -309,17 +309,18 @@ public class AuthController {
public ResponseEntity<Resource> getAvatarFile() {
User user = authHelper.getAuthenticatedUser();
if (!avatarStorageService.hasAvatar(user)) {
return ResponseEntity.notFound().build();
if (avatarStorageService.hasAvatar(user)) {
try {
Resource resource = avatarStorageService.loadAvatarResource(user);
MediaType mediaType = avatarStorageService.resolveMediaType(user);
return ResponseEntity.ok().contentType(mediaType).body(resource);
} catch (IllegalArgumentException ignored) {
}
}
try {
Resource resource = avatarStorageService.loadAvatarResource(user);
MediaType mediaType = avatarStorageService.resolveMediaType(user);
return ResponseEntity.ok().contentType(mediaType).body(resource);
} catch (IllegalArgumentException ex) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok()
.contentType(MediaType.valueOf("image/svg+xml"))
.body(avatarStorageService.loadDefaultAvatarResource());
}
@DeleteMapping("/me/avatar")

View File

@@ -7,6 +7,7 @@ import com.petshop.backend.repository.UserRepository;
import com.petshop.backend.service.AvatarStorageService;
import com.petshop.backend.util.ImageValidationUtil;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
@@ -42,18 +43,23 @@ public class UserAvatarController {
@PreAuthorize("isAuthenticated()")
public ResponseEntity<Resource> getUserAvatarFile(@PathVariable Long userId) {
User user = userRepository.findById(userId).orElse(null);
if (user == null || !avatarStorageService.hasAvatar(user)) {
if (user == null) {
return ResponseEntity.notFound().build();
}
try {
Resource resource = avatarStorageService.loadAvatarResource(user);
return ResponseEntity.ok()
.contentType(avatarStorageService.resolveMediaType(user))
.body(resource);
} catch (IllegalArgumentException ex) {
return ResponseEntity.notFound().build();
if (avatarStorageService.hasAvatar(user)) {
try {
Resource resource = avatarStorageService.loadAvatarResource(user);
return ResponseEntity.ok()
.contentType(avatarStorageService.resolveMediaType(user))
.body(resource);
} catch (IllegalArgumentException ignored) {
}
}
return ResponseEntity.ok()
.contentType(MediaType.valueOf("image/svg+xml"))
.body(avatarStorageService.loadDefaultAvatarResource());
}
@PostMapping("/{userId}/avatar")

View File

@@ -143,7 +143,7 @@ public class AppointmentService {
appointment.setEmployee(employee);
appointment.setAppointmentDate(request.getAppointmentDate());
appointment.setAppointmentTime(request.getAppointmentTime());
appointment.setAppointmentStatus(request.getAppointmentStatus());
appointment.setAppointmentStatus("Scheduled");
appointment.setPet(pet);
appointment = appointmentRepository.save(appointment);
@@ -304,11 +304,9 @@ public class AppointmentService {
}
private void validateAppointmentRequest(AppointmentRequest request) {
if ("Booked".equalsIgnoreCase(request.getAppointmentStatus())) {
LocalDateTime appointmentDateTime = LocalDateTime.of(request.getAppointmentDate(), request.getAppointmentTime());
if (appointmentDateTime.isBefore(LocalDateTime.now())) {
throw new BusinessException("Booked appointments must be scheduled in the future");
}
LocalDateTime appointmentDateTime = LocalDateTime.of(request.getAppointmentDate(), request.getAppointmentTime());
if (appointmentDateTime.isBefore(LocalDateTime.now())) {
throw new BusinessException("Appointments must be scheduled in the future");
}
}

View File

@@ -13,6 +13,7 @@ import org.springframework.web.multipart.MultipartFile;
import jakarta.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -54,7 +55,11 @@ public class AvatarStorageService {
public Resource loadAvatarResource(User user) {
String filename = extractFilename(user.getAvatarUrl());
if (blobService.isEnabled()) {
return new ByteArrayResource(blobService.download(BLOB_CONTAINER, filename));
try {
return new ByteArrayResource(blobService.download(BLOB_CONTAINER, filename));
} catch (Exception ex) {
throw new IllegalArgumentException("Avatar file was not found");
}
}
Path filePath = resolveStoredAvatarPath(user.getAvatarUrl());
if (!Files.exists(filePath) || !Files.isRegularFile(filePath)) {
@@ -63,6 +68,18 @@ public class AvatarStorageService {
return new PathResource(filePath);
}
public Resource loadDefaultAvatarResource() {
InputStream is = getClass().getResourceAsStream("/static/default-avatar.svg");
if (is == null) {
throw new IllegalStateException("Default avatar resource not found");
}
try {
return new ByteArrayResource(is.readAllBytes());
} catch (IOException e) {
throw new IllegalStateException("Failed to read default avatar", e);
}
}
public void deleteAvatar(User user) throws IOException {
if (user.getAvatarUrl() == null || user.getAvatarUrl().isBlank()) return;
if (blobService.isEnabled()) {
@@ -80,7 +97,7 @@ public class AvatarStorageService {
}
public String toOwnerAvatarUrl(User user) {
return hasAvatar(user) ? "/api/v1/users/" + user.getId() + "/avatar/file" : null;
return "/api/v1/users/" + user.getId() + "/avatar/file";
}
public String toStoredAvatarUrl(String avatarFilenamePath) {

View File

@@ -146,6 +146,12 @@ public class ChatService {
}
}
boolean hasContent = request.getContent() != null && !request.getContent().isBlank();
boolean hasAttachment = request.getAttachmentUrl() != null && !request.getAttachmentUrl().isBlank();
if (!hasContent && !hasAttachment) {
throw new BusinessException("Message must have content or an attachment");
}
ContentFilter.validate(request.getContent());
Message message = new Message();

View File

@@ -89,6 +89,10 @@ public class CouponService {
}
private void updateCouponFields(Coupon coupon, CouponRequest request) {
if ("PERCENTAGE".equalsIgnoreCase(request.getDiscountType())
&& request.getDiscountValue().compareTo(new BigDecimal("100")) >= 0) {
throw new BusinessException("Percentage discount must be less than 100");
}
coupon.setCouponCode(request.getCouponCode());
coupon.setDiscountType(request.getDiscountType());
coupon.setDiscountValue(request.getDiscountValue());

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" width="128" height="128"><circle cx="64" cy="64" r="64" fill="#9e9e9e"/><circle cx="64" cy="50" r="22" fill="#fff"/><ellipse cx="64" cy="114" rx="40" ry="36" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 240 B