Skip to content
Snippets Groups Projects
Commit c9bcc199 authored by Birk Øvstetun Narvhus's avatar Birk Øvstetun Narvhus
Browse files

Merge branch 'Epic/1-product-endpoint' into 'main'

Resolve "Product endpoint"

Closes #1

See merge request idatt2106-v23-03/backend!112
parents 317271ce 8fd5fcaa
No related branches found
No related tags found
No related merge requests found
package ntnu.idatt2016.v233.SmartMat.controller.product;
import lombok.AllArgsConstructor;
import ntnu.idatt2016.v233.SmartMat.dto.request.ProductRequest;
import ntnu.idatt2016.v233.SmartMat.entity.product.Product;
import ntnu.idatt2016.v233.SmartMat.service.product.ProductService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
/**
* The product controller is responsible for handling requests related to products.
* It uses the product service to handle the requests.
* @version 1.0
* @Author Birk
* @since 26.04.2023
*/
@RestController
@AllArgsConstructor
@RequestMapping("/api/product")
public class ProductController {
private final ProductService productService;
/**
* Creates a product if it does not already exist.
* @param productRequest The product to be registered.
* @return The product that was registered.
*/
@PostMapping("/")
public ResponseEntity<Product> createProduct(@RequestBody ProductRequest productRequest) {
Product product = Product.builder()
.ean(productRequest.ean())
.name(productRequest.name())
.description(productRequest.description())
.url(productRequest.image())
.build();
if(productService.getProductById(productRequest.ean()).isPresent())
return ResponseEntity.status(409).build();
Optional<List<String>> volumeUnit = productService.getProductVolume(productRequest.ean());
if(volumeUnit.isPresent()){
product.setUnit(volumeUnit.get().get(1));
product.setAmount(Double.parseDouble(volumeUnit.get().get(0)));
}
productService.saveProduct(product);
return ResponseEntity.ok(product);
}
/**
* Returns a product with the given ean.
* @param ean The ean of the product to be returned.
* @return The product with the given ean.
*/
@GetMapping("ean/{ean}")
public ResponseEntity<Product> getProduct(@PathVariable long ean) {
return productService.getProductById(ean)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
/**
* Returns all products in the database.
* @return All products in the database.
*/
@GetMapping("/")
public ResponseEntity<List<Product>> getAllProducts() {
return ResponseEntity.ok(productService.getAllProducts());
}
/**
* Deletes a product with the given ean.
* @param ean The ean of the product to be deleted.
* @return The product that was deleted.
*/
@DeleteMapping("ean/{ean}")
public ResponseEntity<Product> deleteProduct(@PathVariable long ean) {
Optional<Product> product = productService.getProductById(ean);
if(product.isPresent()) {
productService.deleteProductById(product.get().getEan());
return ResponseEntity.ok(product.get());
}
return ResponseEntity.notFound().build();
}
/**
* Updates a product with the given ean.
* @param ean The ean of the product to be updated.
* @param productRequest The product to be updated.
* @return The product that was updated.
*/
@PutMapping("ean/{ean}")
public ResponseEntity<Product> updateProduct(@PathVariable long ean, @RequestBody ProductRequest productRequest) {
Optional<Product> product = productService.getProductById(ean);
if(product.isPresent()) {
product.get().setName(productRequest.name());
product.get().setDescription(productRequest.description());
product.get().setUrl(productRequest.image());
Optional<List<String>> volumeUnit = productService.getProductVolume(productRequest.ean());
if(volumeUnit.isPresent()){
product.get().setUnit(volumeUnit.get().get(1));
product.get().setAmount(Double.parseDouble(volumeUnit.get().get(0)));
}
productService.updateProduct(product.get());
return ResponseEntity.ok(product.get());
}
return ResponseEntity.notFound().build();
}
}
package ntnu.idatt2016.v233.SmartMat.dto.request;
import lombok.Builder;
@Builder
public record ProductRequest(long ean, String name, String description, String image, double price) {
}
......@@ -35,6 +35,7 @@ public class Product{
@Column(name = "description")
String description;
@ManyToOne
@JoinColumn(name = "category_name")
@JsonIgnoreProperties({"products"})
......
......@@ -76,7 +76,7 @@ public class ProductService {
* @param id The id of the product to get the volume from
* @return The volume of the product, if it exists
*/
public Optional<String> getProductVolume(long id) {
public Optional<List<String>> getProductVolume(long id) {
if(productRepository.findById(id).isEmpty())
return Optional.empty();
......
......@@ -5,6 +5,7 @@ import ntnu.idatt2016.v233.SmartMat.entity.product.Product;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;
/**
* Utility class for products
......@@ -26,7 +27,7 @@ public class ProductUtil {
* @param product The product to get the volume from
* @return The volume of the product, if it exists
*/
public static Optional<String> getVolumeFromProduct(Product product) {
public static Optional<List<String>> getVolumeFromProduct(Product product) {
for (String desc : Arrays.asList(product.getName(), product.getDescription())) {
List<String> words = List.of(desc.split(" "));
if (words.size() > 1) {
......@@ -34,16 +35,25 @@ public class ProductUtil {
for (String unit : VOLUME_UNITS) {
int i = words.indexOf(unit);
if (i != -1) {
return Optional.of(words.get(i - 1) + unit);
return Optional.of(List.of(words.get(i - 1), unit));
}
}
volume = words.stream().filter(word -> Arrays.stream(VOLUME_UNITS).anyMatch(word::contains))
volume = words.stream().map(word -> Arrays.stream(VOLUME_UNITS).map(unit -> {
int index = word.indexOf(unit);
if (index == -1) {
if (!Pattern.matches("[a-zA-Z]+", word) && ProductUtil.hasNumbers(word)) {
return word;
}
return "";
}
return word.substring(0, index) + " " + word.substring(index);
}).findAny().orElse(""))
.filter(ProductUtil::hasNumbers)
.findAny()
.orElse("");
if (!volume.equals("")){
return Optional.of(volume);
return Optional.of(List.of(volume.split(" ")));
}
}
}
......
package ntnu.idatt2016.v233.SmartMat.controller.product;
import ntnu.idatt2016.v233.SmartMat.dto.request.ProductRequest;
import ntnu.idatt2016.v233.SmartMat.entity.product.Product;
import ntnu.idatt2016.v233.SmartMat.service.product.ProductService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
public class ProductControllerTest {
@Mock
private ProductService productService;
@InjectMocks
private ProductController productController;
@Test
public void createProduct_productDoesNotExist_returnsCreatedProduct() {
// Arrange
ProductRequest productRequest = ProductRequest.builder()
.ean(123L)
.name("Test Product")
.description("A test product")
.image("http://test.com/image.jpg")
.build();
when(productService.getProductById(123L)).thenReturn(Optional.empty());
when(productService.getProductVolume(123L)).thenReturn(Optional.of(List.of("1", "kg")));
// Act
ResponseEntity<Product> response = productController.createProduct(productRequest);
Product product = response.getBody();
// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(123L, product.getEan());
assertEquals("Test Product", product.getName());
assertEquals("A test product", product.getDescription());
assertEquals("http://test.com/image.jpg", product.getUrl());
assertEquals("kg", product.getUnit());
assertEquals(1.0, product.getAmount());
}
@Test
public void createProduct_productExists_returnsConflict() {
// Arrange
ProductRequest productRequest = ProductRequest.builder()
.ean(123L)
.name("Test Product")
.description("A test product")
.image("http://test.com/image.jpg")
.build();
when(productService.getProductById(123L)).thenReturn(Optional.of(new Product()));
// Act
ResponseEntity<Product> response = productController.createProduct(productRequest);
// Assert
assertEquals(HttpStatus.CONFLICT, response.getStatusCode());
assertFalse(response.hasBody());
}
@Test
public void getProduct_productExists_returnsProduct() {
// Arrange
Product product = new Product();
product.setEan(123L);
product.setName("Test Product");
when(productService.getProductById(123L)).thenReturn(Optional.of(product));
// Act
ResponseEntity<Product> response = productController.getProduct(123L);
Product result = response.getBody();
// Assert
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals(123L, result.getEan());
assertEquals("Test Product", result.getName());
}
@Test
public void getProduct_productDoesNotExist_returnsNotFound() {
// Arrange
when(productService.getProductById(123L)).thenReturn(Optional.empty());
// Act
ResponseEntity<Product> response = productController.getProduct(123L);
// Assert
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
assertFalse(response.hasBody());
}
}
\ No newline at end of file
......@@ -133,9 +133,9 @@ public class ProductServiceTest {
ProductService productService = new ProductService(mockRepository);
// Verify that the service returns the correct volume
Optional<String> returnedVolume = productService.getProductVolume(productId);
Optional<List<String>> returnedVolume = productService.getProductVolume(productId);
assertTrue(returnedVolume.isPresent());
assertEquals("500ml", returnedVolume.get());
assertEquals(List.of("500", "ml"), returnedVolume.get());
}
@Test
......@@ -150,7 +150,7 @@ public class ProductServiceTest {
ProductService productService = new ProductService(mockRepository);
// Verify that the service returns an empty optional
Optional<String> returnedVolume = productService.getProductVolume(productId);
Optional<List<String>> returnedVolume = productService.getProductVolume(productId);
assertTrue(returnedVolume.isEmpty());
}
......
......@@ -4,6 +4,8 @@ import ntnu.idatt2016.v233.SmartMat.entity.product.Product;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class ProductUtilTest {
......@@ -20,7 +22,7 @@ class ProductUtilTest {
@Test
void getVolumeFromProduct() {
assertEquals("24x500ml", ProductUtil.getVolumeFromProduct(product).get());
assertEquals(List.of("24x500", "ml"), ProductUtil.getVolumeFromProduct(product).get());
this.product = Product.builder()
.ean(123456789)
......@@ -28,7 +30,7 @@ class ProductUtilTest {
.description("Pepsi Original 24x500 ml")
.build();
assertEquals("24x500ml", ProductUtil.getVolumeFromProduct(product).get());
assertEquals(List.of("24x500", "ml"), ProductUtil.getVolumeFromProduct(product).get());
this.product = Product.builder()
.ean(123456789)
......@@ -37,7 +39,7 @@ class ProductUtilTest {
.build();
assertEquals("24x500ml", ProductUtil.getVolumeFromProduct(product).get());
assertEquals(List.of("24x500", "ml"), ProductUtil.getVolumeFromProduct(product).get());
this.product = Product.builder()
.ean(123456789)
......@@ -46,6 +48,6 @@ class ProductUtilTest {
.build();
assertEquals("24x500ml", ProductUtil.getVolumeFromProduct(product).get());
assertEquals(List.of("24x500", "ml"), ProductUtil.getVolumeFromProduct(product).get());
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment