diff --git a/build.gradle b/build.gradle index 38ef182..b5f8c19 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,13 @@ jar { dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-devtools' + implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect' + + implementation 'org.webjars.npm:bootstrap:5.3.0-alpha2' + implementation 'org.webjars:jquery:3.6.0' + implementation 'org.webjars:font-awesome:6.1.0' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'com.h2database:h2:2.1.210' @@ -25,9 +32,7 @@ dependencies { implementation 'org.hibernate.validator:hibernate-validator' implementation 'org.springdoc:springdoc-openapi-ui:1.6.5' - - - + implementation 'org.projectlombok:lombok:1.18.22' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/src/main/java/com/example/demo/WebConfiguration.java b/src/main/java/com/example/demo/WebConfiguration.java index 84883a8..ba35358 100644 --- a/src/main/java/com/example/demo/WebConfiguration.java +++ b/src/main/java/com/example/demo/WebConfiguration.java @@ -12,6 +12,7 @@ import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfiguration implements WebMvcConfigurer { + public static final String REST_API = "/api"; @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedMethods("*"); @@ -22,9 +23,6 @@ public class WebConfiguration implements WebMvcConfigurer { ViewControllerRegistration registration = registry.addViewController("/notFound"); registration.setViewName("forward:/index.html"); registration.setStatusCode(HttpStatus.OK); - - // Alternative way (404 error hits the console): - // > registry.addViewController("/notFound").setViewName("forward:/index.html"); } @Bean diff --git a/src/main/java/com/example/demo/master/MasterController.java b/src/main/java/com/example/demo/master/MasterController.java index 5d1f206..792188a 100644 --- a/src/main/java/com/example/demo/master/MasterController.java +++ b/src/main/java/com/example/demo/master/MasterController.java @@ -1,5 +1,6 @@ package com.example.demo.master; +import com.example.demo.WebConfiguration; import com.example.demo.order.OrderService; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -13,11 +14,11 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController -@RequestMapping("/master") +@RequestMapping(WebConfiguration.REST_API + "/master") public class MasterController { private final MasterService masterService; private final OrderService orderService; - private Long currentMasterId = 0L; + public MasterController(MasterService masterService, OrderService orderService) { this.masterService = masterService; @@ -26,14 +27,14 @@ public class MasterController { @GetMapping("/") public MasterDto getCurrentMaster() { - return new MasterDto(masterService.findMaster(currentMasterId)); + return new MasterDto(masterService.findMaster(masterService.getCurrentMasterId())); } @GetMapping("/{email}/{password}") public MasterDto getCurrentMaster(@PathVariable("email") String email, @PathVariable("password") String password) { var master = new MasterDto(masterService.findMaster(email, password)); - currentMasterId = master.getId(); + masterService.setCurrentMasterId(master.getId()); return master; } @PostMapping("/") @@ -42,29 +43,29 @@ public class MasterController { @RequestParam("email") String email, @RequestParam("password") String password) { MasterDto master = new MasterDto(masterService.addMaster(firstName, lastName, email, password)); - currentMasterId = master.getId(); - orderService.addOrder(currentMasterId); + masterService.setCurrentMasterId(master.getId()); + orderService.addOrder(master.getId()); return master; } - @PatchMapping("/{id}") - public MasterDto updateMaster(@PathVariable Long id, - @RequestParam("firstName") String firstName, + @PatchMapping("/") + public MasterDto updateMaster(@RequestParam("firstName") String firstName, @RequestParam("lastName") String lastName, @RequestParam("email") String email, @RequestParam("password") String password) { - return new MasterDto(masterService.updateMaster(id, firstName, lastName, email, password)); + return new MasterDto(masterService.updateMaster(masterService.getCurrentMasterId(), + firstName, lastName, email, password)); } - @DeleteMapping("/{id}") + @DeleteMapping("/") public MasterDto deleteMaster(@PathVariable Long id) { - return new MasterDto(masterService.deleteMaster(id)); + return new MasterDto(masterService.deleteMaster(masterService.getCurrentMasterId())); } @PostMapping("/log_out") public void logOut() { - currentMasterId = 0L; + masterService.setCurrentMasterId(0L); } } diff --git a/src/main/java/com/example/demo/master/MasterMvcController.java b/src/main/java/com/example/demo/master/MasterMvcController.java new file mode 100644 index 0000000..115decb --- /dev/null +++ b/src/main/java/com/example/demo/master/MasterMvcController.java @@ -0,0 +1,84 @@ +package com.example.demo.master; + +import com.example.demo.order.OrderService; +import com.example.demo.product.ProductDto; +import com.example.demo.product.ProductService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +@Controller +@RequestMapping("/master") +public class MasterMvcController { + private final MasterService masterService; + private final OrderService orderService; + + public MasterMvcController(MasterService masterService, OrderService orderService) { + this.masterService = masterService; + this.orderService = orderService; + } + + @GetMapping("/login") + public String loginPage(Model model) { + if (masterService.getCurrentMasterId() != 0) { + return "redirect:/product"; + } + model.addAttribute("user", new Master()); + return "Login"; + } + + @PostMapping("/login") + public String login(@ModelAttribute Master user) { + var master = new MasterDto(masterService.findMaster(user.getEmail(), user.getPassword())); + masterService.setCurrentMasterId(master.getId()); + return "redirect:/product/my_products"; + } + + @GetMapping("") + public String getUserPage(Model model) { + if (masterService.getCurrentMasterId() != 0) { + model.addAttribute("user", masterService.findMaster(masterService.getCurrentMasterId())); + } else { + return "redirect:/master/register"; + } + return "UserPage"; + } + + @PostMapping(value = "", params = "action=update") + public String updateUserPage(@ModelAttribute Master user) { + if (masterService.getCurrentMasterId() == 0) { + return "redirect:/master"; + } + masterService.updateMaster( + masterService.getCurrentMasterId(), + user.getFirstName(), + user.getLastName(), + user.getEmail(), + user.getPassword()); + return "redirect:/product"; + } + + @PostMapping(value = "", params = "action=log_out") + public String logOut() { + masterService.setCurrentMasterId(0L); + return "redirect:/product"; + } + + @GetMapping("/register") + public String registerPage(Model model) { + model.addAttribute("user", new Master()); + return "UserPage"; + } + + @PostMapping(value = "/register", params = "action=register") + public String register(@ModelAttribute Master user) { + MasterDto master = new MasterDto(masterService.addMaster( + user.getFirstName(), + user.getLastName(), + user.getEmail(), + user.getPassword())); + masterService.setCurrentMasterId(master.getId()); + orderService.addOrder(master.getId()); + return "redirect:/product/my_products"; + } +} diff --git a/src/main/java/com/example/demo/master/MasterService.java b/src/main/java/com/example/demo/master/MasterService.java index 1970d8f..d45af85 100644 --- a/src/main/java/com/example/demo/master/MasterService.java +++ b/src/main/java/com/example/demo/master/MasterService.java @@ -1,5 +1,6 @@ package com.example.demo.master; +import com.example.demo.order.Order; import com.example.demo.order.OrderController; import com.example.demo.order.OrderService; import com.example.demo.util.validation.ValidatorUtil; @@ -16,6 +17,8 @@ public class MasterService { private final ValidatorUtil validatorUtil; + private Long currentMasterId = 0L; + public MasterService(MasterRepository masterRepository, ValidatorUtil validatorUtil) { this.masterRepository = masterRepository; this.validatorUtil = validatorUtil; @@ -34,6 +37,7 @@ public class MasterService { return mater.orElseThrow(() -> new MasterNotFoundException(id)); } + @Transactional(readOnly = true) public Master findMaster(String email, String password) { final Optional master = masterRepository.findByEmail(email); @@ -72,6 +76,14 @@ public class MasterService { masterRepository.deleteAll(); } + @Transactional + public Long getCurrentMasterId (){ + return currentMasterId; + } + @Transactional + public void setCurrentMasterId(Long masterId) { + currentMasterId = masterId; + } } diff --git a/src/main/java/com/example/demo/order/OrderController.java b/src/main/java/com/example/demo/order/OrderController.java index 859cc60..ab8a710 100644 --- a/src/main/java/com/example/demo/order/OrderController.java +++ b/src/main/java/com/example/demo/order/OrderController.java @@ -1,5 +1,7 @@ package com.example.demo.order; +import com.example.demo.WebConfiguration; +import com.example.demo.master.MasterService; import com.example.demo.product.Product; import com.example.demo.product.ProductDto; import com.example.demo.product.ProductService; @@ -10,12 +12,14 @@ import java.util.ArrayList; import java.util.List; @RestController -@RequestMapping("/order") +@RequestMapping(WebConfiguration.REST_API + "/order") public class OrderController { private final OrderService orderService; + private final MasterService masterService; - public OrderController(OrderService orderService) { + public OrderController(OrderService orderService, MasterService masterService) { this.orderService = orderService; + this.masterService = masterService; } @GetMapping("/{id}") @@ -23,9 +27,9 @@ public class OrderController { return new OrderDto(orderService.findOrder(id)); } - @DeleteMapping("/{id}") - public void buyProducts(@PathVariable Long id) { - orderService.buyProducts(id); + @DeleteMapping("/") + public void buyProducts() { + orderService.buyProducts(masterService.getCurrentMasterId()); } @GetMapping("/") @@ -38,16 +42,14 @@ public class OrderController { return new OrderDto(orderService.addOrder(masterId)); } - @PostMapping("{id}/{product}") - public void addProduct(@PathVariable("id") Long id, - @PathVariable("product") Long productId) { - orderService.addProduct(id, productId); + @PostMapping("/{product}") + public void addProduct(@PathVariable("product") Long productId) { + orderService.addProduct(masterService.getCurrentMasterId(), productId); } - @DeleteMapping("{id}/{product}") - public void deleteProduct(@PathVariable("id") Long id, - @PathVariable("product") Long productId) { - orderService.deleteProduct(id, productId); + @DeleteMapping("{product}") + public void deleteProduct(@PathVariable("product") Long productId) { + orderService.deleteProduct(masterService.getCurrentMasterId(), productId); } @DeleteMapping("/") public void deleteOrders() { diff --git a/src/main/java/com/example/demo/order/OrderMvcController.java b/src/main/java/com/example/demo/order/OrderMvcController.java new file mode 100644 index 0000000..db14635 --- /dev/null +++ b/src/main/java/com/example/demo/order/OrderMvcController.java @@ -0,0 +1,49 @@ +package com.example.demo.order; + +import com.example.demo.master.MasterService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.concurrent.atomic.AtomicInteger; + +@Controller +@RequestMapping("/order") +public class OrderMvcController { + private final MasterService masterService; + private final OrderService orderService; + + public OrderMvcController(MasterService masterService, OrderService orderService) { + this.masterService = masterService; + this.orderService = orderService; + } + + @GetMapping("") + public String getOrder(Model model) { + if (masterService.getCurrentMasterId() == 0) { + return "redirect:/master/login"; + } + model.addAttribute("user", masterService.findMaster(masterService.getCurrentMasterId())); + model.addAttribute("order", orderService.findOrder(masterService.getCurrentMasterId())); + AtomicInteger fullCost = new AtomicInteger(); + orderService.findOrder(masterService.getCurrentMasterId()).getProducts().forEach( + item -> fullCost.addAndGet(item.getCost())); + model.addAttribute("fullCost", fullCost); + return "OrderPage"; + } + + @PostMapping(value = "", params = "action=delete") + public String deleteProduct(@RequestParam(value = "id", required = true) Long id) { + orderService.deleteProduct(masterService.getCurrentMasterId(), id); + return "redirect:/order"; + } + + @PostMapping(value = "", params = "action=buy") + public String buyProducts() { + orderService.buyProducts(masterService.getCurrentMasterId()); + return "redirect:/product"; + } +} diff --git a/src/main/java/com/example/demo/order/OrderService.java b/src/main/java/com/example/demo/order/OrderService.java index 5763949..dab795b 100644 --- a/src/main/java/com/example/demo/order/OrderService.java +++ b/src/main/java/com/example/demo/order/OrderService.java @@ -42,7 +42,8 @@ public class OrderService { @Transactional public void addProduct(Long masterId, Long productId) { - final Order order = orderRepository.findByMaster(masterRepository.findById(masterId).orElseThrow(() -> new MasterNotFoundException(masterId))).orElseThrow(() -> new OrderNotFoundException(masterId)); + final Order order = orderRepository.findByMaster(masterRepository.findById(masterId).orElseThrow( + () -> new MasterNotFoundException(masterId))).orElseThrow(() -> new OrderNotFoundException(masterId)); final Product product = productRepository.findById(productId).orElseThrow(() -> new ProductNotFoundException(productId)); order.addProduct(product); @@ -54,7 +55,8 @@ public class OrderService { @Transactional public void buyProducts(Long masterId) { - final Order order = orderRepository.findByMaster(masterRepository.findById(masterId).orElseThrow(() -> new MasterNotFoundException(masterId))).orElseThrow(() -> new OrderNotFoundException(masterId)); + final Order order = orderRepository.findByMaster(masterRepository.findById(masterId).orElseThrow( + () -> new MasterNotFoundException(masterId))).orElseThrow(() -> new OrderNotFoundException(masterId)); var products = new ArrayList(order.getProducts()); for (var item: products) { item.setAvailable(Status.Bought); @@ -66,7 +68,8 @@ public class OrderService { @Transactional public void deleteProduct(Long masterId, Long productId) { - final Order order = orderRepository.findByMaster(masterRepository.findById(masterId).orElseThrow(() -> new MasterNotFoundException(masterId))).orElseThrow(() -> new OrderNotFoundException(masterId)); + final Order order = orderRepository.findByMaster(masterRepository.findById(masterId).orElseThrow( + () -> new MasterNotFoundException(masterId))).orElseThrow(() -> new OrderNotFoundException(masterId)); final Product product = productRepository.findById(productId).orElseThrow(() -> new ProductNotFoundException(productId)); order.removeProduct(product); @@ -78,7 +81,9 @@ public class OrderService { @Transactional() public Order findOrder(Long masterId) { - final Order order = orderRepository.findByMaster(masterRepository.findById(masterId).orElseThrow(() -> new MasterNotFoundException(masterId))).orElseThrow(() -> new OrderNotFoundException(masterId)); + final Order order = orderRepository.findByMaster(masterRepository.findById(masterId). + orElseThrow(() -> new MasterNotFoundException(masterId))).orElseThrow( + () -> new OrderNotFoundException(masterId)); return order; } diff --git a/src/main/java/com/example/demo/product/Product.java b/src/main/java/com/example/demo/product/Product.java index fbb66f3..a988ff2 100644 --- a/src/main/java/com/example/demo/product/Product.java +++ b/src/main/java/com/example/demo/product/Product.java @@ -73,7 +73,7 @@ public class Product { public String toString() { return "Product {" + "id=" + id + - ", firstName='" + name + '\'' + + ", name='" + name + '\'' + ", cost='" + cost.toString() + '\'' + ", master='" + master.toString() + '\'' + '}'; diff --git a/src/main/java/com/example/demo/product/ProductController.java b/src/main/java/com/example/demo/product/ProductController.java index 0cf5689..11204f6 100644 --- a/src/main/java/com/example/demo/product/ProductController.java +++ b/src/main/java/com/example/demo/product/ProductController.java @@ -1,5 +1,6 @@ package com.example.demo.product; +import com.example.demo.WebConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; @@ -12,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController -@RequestMapping("/product") +@RequestMapping(WebConfiguration.REST_API + "/product") public class ProductController { private final ProductService productService; diff --git a/src/main/java/com/example/demo/product/ProductMvcController.java b/src/main/java/com/example/demo/product/ProductMvcController.java new file mode 100644 index 0000000..4b83fdd --- /dev/null +++ b/src/main/java/com/example/demo/product/ProductMvcController.java @@ -0,0 +1,102 @@ +package com.example.demo.product; + +import com.example.demo.master.Master; +import com.example.demo.master.MasterService; +import com.example.demo.order.OrderService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + + +@Controller +@RequestMapping("/product") +public class ProductMvcController { + private final ProductService productService; + private final MasterService masterService; + private final OrderService orderService; + public ProductMvcController(MasterService masterService, + ProductService productService, + OrderService orderService) { + this.masterService = masterService; + this.productService = productService; + this.orderService = orderService; + } + + @GetMapping("") + public String getProducts(Model model) { + if (masterService.getCurrentMasterId() != 0) { + Master user = masterService.findMaster(masterService.getCurrentMasterId()); + model.addAttribute("user", user); + } + else { + model.addAttribute("user", new Master()); + } + model.addAttribute("products", productService.findAllProducts() + .stream().map(ProductDto::new).toList()); + return "Products"; + } + + @PostMapping("") + public String addProductToOrder(@RequestParam(value = "id", required = true) Long id) { + if (masterService.getCurrentMasterId() == 0) { + return "redirect:/master/login"; + } + orderService.addProduct(masterService.getCurrentMasterId(), id); + return "redirect:/product"; + } + + + @GetMapping("/my_products") + public String getMasterProduct(Model model) { + if (masterService.getCurrentMasterId() == 0) { + return "redirect:/product"; + } + model.addAttribute("user", + masterService.findMaster(masterService.getCurrentMasterId())); + model.addAttribute("products", + productService.findProducts(masterService.getCurrentMasterId()).stream().map(ProductDto::new).toList()); + return "UserProducts"; + } + + @GetMapping("/create_product") + public String createProductPage(Model model) { + if (masterService.getCurrentMasterId() == 0) { + return "redirect:/product"; + } + model.addAttribute("user", masterService.findMaster(masterService.getCurrentMasterId())); + model.addAttribute("product", new Product()); + model.addAttribute("buttonText", "Create"); + return "ProductCreate"; + } + + @PostMapping("/create_product") + public String createProduct(@ModelAttribute Product product) { + productService.addProduct( + product.getName(), + product.getCost(), + masterService.getCurrentMasterId() + ); + return "redirect:/product/my_products"; + } + + @GetMapping("/update_product/{id}") + public String updateProductPage(Model model, @PathVariable("id") Long id) { + if (masterService.getCurrentMasterId() == 0) { + return "redirect:/product"; + } + model.addAttribute("user", masterService.findMaster(masterService.getCurrentMasterId())); + model.addAttribute("product", productService.findProduct(id)); + model.addAttribute("buttonText", "Update"); + return "ProductCreate"; + } + + @PostMapping("/update_product/{id}") + public String createProduct(@ModelAttribute Product product, @PathVariable("id") Long id) { + productService.updateProduct( + id, + product.getName(), + product.getCost() + ); + return "redirect:/product/my_products"; + } +} diff --git a/src/main/resources/static/style.css b/src/main/resources/static/style.css new file mode 100644 index 0000000..07b9627 --- /dev/null +++ b/src/main/resources/static/style.css @@ -0,0 +1,25 @@ +body { + background: #f54d9a; +} + +.logo { + background: #FF9CCE; +} + +main { + padding: 2%; + margin: 10% 5%; +} + +main img { + width: 100%; + object-fit: cover; +} + +form { + padding: 1%; +} + +.product-div { + background: #e874ac; +} \ No newline at end of file diff --git a/src/main/resources/templates/Header.html b/src/main/resources/templates/Header.html new file mode 100644 index 0000000..d96014c --- /dev/null +++ b/src/main/resources/templates/Header.html @@ -0,0 +1,37 @@ + + + + + Title + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/Login.html b/src/main/resources/templates/Login.html new file mode 100644 index 0000000..4a492e4 --- /dev/null +++ b/src/main/resources/templates/Login.html @@ -0,0 +1,38 @@ + + + + + Login + + + + + + +
+
+
+
+ +
+
+ +
+
+ +
+
+ Register +
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/OrderPage.html b/src/main/resources/templates/OrderPage.html new file mode 100644 index 0000000..e23acc9 --- /dev/null +++ b/src/main/resources/templates/OrderPage.html @@ -0,0 +1,48 @@ + + + + + Login + + + + + + +
+
+

Order

+
+
+
+ +
+

+
+
+

+
+
+ +
+
+
+
+

+
+
+

+

+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/ProductCreate.html b/src/main/resources/templates/ProductCreate.html new file mode 100644 index 0000000..dbb20ad --- /dev/null +++ b/src/main/resources/templates/ProductCreate.html @@ -0,0 +1,27 @@ + + + + + Login + + + + + + +
+
+
+ + + +
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/Products.html b/src/main/resources/templates/Products.html new file mode 100644 index 0000000..9b701d2 --- /dev/null +++ b/src/main/resources/templates/Products.html @@ -0,0 +1,38 @@ + + + + + Title + + + + + + +
+ +
+
+
+ +
+

+
+
+

+
+
+ +
+
+
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/UserPage.html b/src/main/resources/templates/UserPage.html new file mode 100644 index 0000000..413e22a --- /dev/null +++ b/src/main/resources/templates/UserPage.html @@ -0,0 +1,55 @@ + + + + + Title + + + + + + +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+ +
+
+ +
+
+
+ +
+
+ Sing In +
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/UserProducts.html b/src/main/resources/templates/UserProducts.html new file mode 100644 index 0000000..909ce73 --- /dev/null +++ b/src/main/resources/templates/UserProducts.html @@ -0,0 +1,37 @@ + + + + + Title + + + + + + + +
+
+
+ Create +
+
+
+

+
+
+

+
+
+ Edit +
+
+
+ + \ No newline at end of file