mirror of
https://gitlab.com/etc404/software-engineering-project.git
synced 2026-05-10 20:52:58 +00:00
Update 2 files
- /src/main/java/com/example/demo/controller/RecipeUploadController.java - /src/main/resources/templates/create-recipe.html
This commit is contained in:
@@ -2,7 +2,6 @@ package com.example.demo.controller;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
@@ -12,6 +11,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
@@ -34,6 +34,9 @@ public class RecipeUploadController {
|
||||
|
||||
private final RecipeService recipeService;
|
||||
|
||||
@Value("${app.upload.dir}")
|
||||
private String uploadDir;
|
||||
|
||||
public RecipeUploadController(RecipeService recipeService) {
|
||||
this.recipeService = recipeService;
|
||||
}
|
||||
@@ -96,7 +99,8 @@ public class RecipeUploadController {
|
||||
String quantityString = getListValue(form.getIngredientQuantity(), i);
|
||||
String quantity = null;
|
||||
if (quantityString != null && !quantityString.isBlank()) {
|
||||
quantity = parseQuantity(quantityString.trim()).toPlainString();
|
||||
quantity = quantityString.trim();
|
||||
validateQuantity(quantity);
|
||||
}
|
||||
|
||||
String unit = getListValue(form.getIngredientUnit(), i);
|
||||
@@ -170,11 +174,11 @@ public class RecipeUploadController {
|
||||
return value == null ? null : value.trim();
|
||||
}
|
||||
|
||||
private BigDecimal parseQuantity(String value) {
|
||||
private void validateQuantity(String value) {
|
||||
String cleaned = value.trim();
|
||||
|
||||
if (cleaned.matches("^\\d+(\\.\\d+)?$")) {
|
||||
return new BigDecimal(cleaned);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cleaned.matches("^\\d+/\\d+$")) {
|
||||
@@ -185,8 +189,10 @@ public class RecipeUploadController {
|
||||
if (denominator.compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new IllegalArgumentException("Ingredient quantity cannot have a zero denominator.");
|
||||
}
|
||||
|
||||
return numerator.divide(denominator, 8, RoundingMode.HALF_UP).stripTrailingZeros();
|
||||
if (numerator.compareTo(BigDecimal.ZERO) < 0 || denominator.compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new IllegalArgumentException("Ingredient quantity must be positive.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (cleaned.matches("^\\d+\\s+\\d+/\\d+$")) {
|
||||
@@ -200,9 +206,12 @@ public class RecipeUploadController {
|
||||
if (denominator.compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new IllegalArgumentException("Ingredient quantity cannot have a zero denominator.");
|
||||
}
|
||||
|
||||
BigDecimal fractionalPart = numerator.divide(denominator, 8, RoundingMode.HALF_UP);
|
||||
return whole.add(fractionalPart).stripTrailingZeros();
|
||||
if (whole.compareTo(BigDecimal.ZERO) < 0
|
||||
|| numerator.compareTo(BigDecimal.ZERO) < 0
|
||||
|| denominator.compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new IllegalArgumentException("Ingredient quantity must be positive.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
@@ -220,12 +229,12 @@ public class RecipeUploadController {
|
||||
|
||||
String storedFilename = UUID.randomUUID() + extension;
|
||||
|
||||
Path uploadDir = Paths.get("uploads");
|
||||
if (!Files.exists(uploadDir)) {
|
||||
Files.createDirectories(uploadDir);
|
||||
Path uploadPath = Paths.get(uploadDir).toAbsolutePath().normalize();
|
||||
if (!Files.exists(uploadPath)) {
|
||||
Files.createDirectories(uploadPath);
|
||||
}
|
||||
|
||||
Path destination = uploadDir.resolve(storedFilename);
|
||||
Path destination = uploadPath.resolve(storedFilename);
|
||||
Files.copy(file.getInputStream(), destination, StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
return "/uploads/" + storedFilename;
|
||||
|
||||
@@ -129,7 +129,7 @@ function addIngredient(data = {}) {
|
||||
row.className = 'dynamic-row';
|
||||
row.innerHTML = `
|
||||
<input type="text" class="ing-name" placeholder="Ingredient (e.g. Sugar)" value="${escapeHtml(data.ingredientName || '')}">
|
||||
<input type="text" class="ing-qty" placeholder="Qty (e.g. 3)" value="${data.quantity ?? ''}">
|
||||
<input type="text" class="ing-qty" placeholder="Qty (e.g. 2, 1/2, 1 1/2)" value="${escapeHtml(data.quantity ?? '')}">
|
||||
<input type="text" class="ing-unit" placeholder="Unit (e.g. tbsp)" value="${escapeHtml(data.unit || '')}">
|
||||
<input type="text" class="ing-notes" placeholder="Notes (optional)" value="${escapeHtml(data.notes || '')}">
|
||||
<button class="btn-remove" title="Remove" type="button">✕</button>`;
|
||||
@@ -283,7 +283,7 @@ function showMessage(message, isError = false) {
|
||||
function showSuccessAndRedirect(message) {
|
||||
showMessage(message, false);
|
||||
setTimeout(() => {
|
||||
window.location.href = '/';
|
||||
window.location.href = '/explore';
|
||||
}, 1500);
|
||||
}
|
||||
|
||||
@@ -317,6 +317,29 @@ function clearAllErrors() {
|
||||
box.textContent = '';
|
||||
}
|
||||
|
||||
function isValidQuantity(val) {
|
||||
const cleaned = String(val ?? '').replace(/\s+/g, ' ').trim();
|
||||
|
||||
if (cleaned === '') return true;
|
||||
|
||||
if (/^\d+(\.\d+)?$/.test(cleaned)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (/^\d+\/\d+$/.test(cleaned)) {
|
||||
const [numerator, denominator] = cleaned.split('/');
|
||||
return Number(numerator) >= 0 && Number(denominator) > 0;
|
||||
}
|
||||
|
||||
if (/^\d+\s\d+\/\d+$/.test(cleaned)) {
|
||||
const [whole, fraction] = cleaned.split(' ');
|
||||
const [numerator, denominator] = fraction.split('/');
|
||||
return Number(whole) >= 0 && Number(numerator) >= 0 && Number(denominator) > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function validateForm() {
|
||||
let valid = true;
|
||||
|
||||
@@ -363,6 +386,7 @@ function validateForm() {
|
||||
|
||||
const ingredientRows = [...document.querySelectorAll('#ingredients-container .dynamic-row')];
|
||||
const filledIngredientRows = ingredientRows.filter(row => row.querySelector('.ing-name').value.trim() !== '');
|
||||
|
||||
if (filledIngredientRows.length === 0 && ingredientRows.length > 0) {
|
||||
showError(ingredientRows[0].querySelector('.ing-name'), 'Add at least one ingredient');
|
||||
valid = false;
|
||||
@@ -371,6 +395,7 @@ function validateForm() {
|
||||
filledIngredientRows.forEach(row => {
|
||||
const nameInput = row.querySelector('.ing-name');
|
||||
const qtyInput = row.querySelector('.ing-qty');
|
||||
|
||||
clearError(nameInput);
|
||||
clearError(qtyInput);
|
||||
|
||||
@@ -384,17 +409,6 @@ function validateForm() {
|
||||
showError(qtyInput, 'Enter a valid quantity (e.g. 2, 1.5, 1/2, 1 1/2) or leave blank');
|
||||
valid = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function isValidQuantity(val) {
|
||||
if (val === '') return true;
|
||||
if (!isNaN(Number(val))) return true;
|
||||
if (/^\d+\/\d+$/.test(val)) return true;
|
||||
if (/^\d+\s+\d+\/\d+$/.test(val)) return true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
const stepAreas = [...document.querySelectorAll('#steps-container textarea')];
|
||||
|
||||
Reference in New Issue
Block a user