diff --git a/pom.xml b/pom.xml index 25bb466d7f..5a590d82d1 100644 --- a/pom.xml +++ b/pom.xml @@ -48,11 +48,41 @@ h2 runtime + + org.projectlombok + lombok + + + org.webjars + bootstrap + 5.2.3 + + + org.webjars + jquery + 3.6.4 + + + com.mysql + mysql-connector-j + 8.0.32 + + + javax.servlet + javax.servlet-api + 4.0.1 + org.springframework.boot spring-boot-starter-test test + + org.junit.jupiter + junit-jupiter + RELEASE + test + @@ -61,6 +91,28 @@ org.springframework.boot spring-boot-maven-plugin + + org.apache.maven.plugins + maven-failsafe-plugin + 2.20 + + + **/*.IT.java + + + ${basedir}/target/classes + + none + + + + + integration-test + verify + + + + diff --git a/src/main/java/guru/springframework/bootstrap/BootStrapMySQL.java b/src/main/java/guru/springframework/bootstrap/BootStrapMySQL.java new file mode 100644 index 0000000000..f665b0ae91 --- /dev/null +++ b/src/main/java/guru/springframework/bootstrap/BootStrapMySQL.java @@ -0,0 +1,91 @@ +package guru.springframework.bootstrap; + +import guru.springframework.domain.Category; +import guru.springframework.domain.UnitOfMeasure; +import guru.springframework.repositories.CategoryRepository; +import guru.springframework.repositories.UnitOfMeasureRepository; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Profile; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@Profile({"dev","prod"}) +public class BootStrapMySQL implements ApplicationListener { + private final CategoryRepository categoryRepository; + private final UnitOfMeasureRepository unitOfMeasureRepository; + + public BootStrapMySQL(CategoryRepository categoryRepository, + UnitOfMeasureRepository unitOfMeasureRepository) { + this.categoryRepository = categoryRepository; + this.unitOfMeasureRepository = unitOfMeasureRepository; + } + + @Override + public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { + + if (categoryRepository.count() == 0L){ + log.debug("Loading Categories"); + loadCategories(); + } + + if (unitOfMeasureRepository.count() == 0L){ + log.debug("Loading UOMs"); + loadUom(); + } + } + + private void loadCategories(){ + Category cat1 = new Category(); + cat1.setDescription("American"); + categoryRepository.save(cat1); + + Category cat2 = new Category(); + cat2.setDescription("Italian"); + categoryRepository.save(cat2); + + Category cat3 = new Category(); + cat3.setDescription("Mexican"); + categoryRepository.save(cat3); + + Category cat4 = new Category(); + cat4.setDescription("Fast Food"); + categoryRepository.save(cat4); + } + + private void loadUom(){ + UnitOfMeasure uom1 = new UnitOfMeasure(); + uom1.setDescription("Teaspoon"); + unitOfMeasureRepository.save(uom1); + + UnitOfMeasure uom2 = new UnitOfMeasure(); + uom2.setDescription("Tablespoon"); + unitOfMeasureRepository.save(uom2); + + UnitOfMeasure uom3 = new UnitOfMeasure(); + uom3.setDescription("Cup"); + unitOfMeasureRepository.save(uom3); + + UnitOfMeasure uom4 = new UnitOfMeasure(); + uom4.setDescription("Pinch"); + unitOfMeasureRepository.save(uom4); + + UnitOfMeasure uom5 = new UnitOfMeasure(); + uom5.setDescription("Ounce"); + unitOfMeasureRepository.save(uom5); + + UnitOfMeasure uom6 = new UnitOfMeasure(); + uom6.setDescription("Each"); + unitOfMeasureRepository.save(uom6); + + UnitOfMeasure uom7 = new UnitOfMeasure(); + uom7.setDescription("Pint"); + unitOfMeasureRepository.save(uom7); + + UnitOfMeasure uom8 = new UnitOfMeasure(); + uom8.setDescription("Dash"); + unitOfMeasureRepository.save(uom8); + } +} diff --git a/src/main/java/guru/springframework/bootstrap/RecipeBootstrap.java b/src/main/java/guru/springframework/bootstrap/RecipeBootstrap.java new file mode 100644 index 0000000000..618b8f4404 --- /dev/null +++ b/src/main/java/guru/springframework/bootstrap/RecipeBootstrap.java @@ -0,0 +1,162 @@ +package guru.springframework.bootstrap; + +import guru.springframework.domain.*; +import guru.springframework.repositories.CategoryRepository; +import guru.springframework.repositories.RecipeRepository; +import guru.springframework.repositories.UnitOfMeasureRepository; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.weaver.ast.Not; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Profile; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +import javax.transaction.Transactional; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +@Slf4j +@Component +@Profile("default") +public class RecipeBootstrap implements ApplicationListener { + private final CategoryRepository categoryRepository; + private final RecipeRepository recipeRepository; + private final UnitOfMeasureRepository unitOfMeasureRepository; + + public RecipeBootstrap(CategoryRepository categoryRepository, RecipeRepository recipeRepository, UnitOfMeasureRepository unitOfMeasureRepository) { + this.categoryRepository = categoryRepository; + this.recipeRepository = recipeRepository; + this.unitOfMeasureRepository = unitOfMeasureRepository; + } + //guardar lo que viene de los repositorios + @Override + @Transactional + public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { + recipeRepository.saveAll(getRecipes()); + log.debug("Loading bootstrap data..."); + } + + private List getRecipes(){ + List recipes = new ArrayList<>(2); + + //get Units Of Measure + Optional eachUomOptional = unitOfMeasureRepository.findByDescription("Each"); + if(!eachUomOptional.isPresent()){ + throw new RuntimeException("Expected Each UOM not found"); + } + Optional tableSpoonUomOptional = unitOfMeasureRepository.findByDescription("Tablespoon"); + if(!tableSpoonUomOptional.isPresent()){ + throw new RuntimeException("Expected Tablespoon UOM not found"); + } + Optional teaSpoonUomOptional = unitOfMeasureRepository.findByDescription("Teaspoon"); + if(!teaSpoonUomOptional.isPresent()){ + throw new RuntimeException("Expected Teaspoon UOM not found"); + } + Optional dashUOMOptional = unitOfMeasureRepository.findByDescription("Dash"); + if(!dashUOMOptional.isPresent()){ + throw new RuntimeException("Expected Dash UOM not found"); + } + Optional pintUOMOptional = unitOfMeasureRepository.findByDescription("Pint"); + if(!pintUOMOptional.isPresent()){ + throw new RuntimeException("Expected Pint UOM not found"); + } + Optional cupsUOMOptional = unitOfMeasureRepository.findByDescription("Cup"); + if(!cupsUOMOptional.isPresent()){ + throw new RuntimeException("Expected Cup UOM not found"); + } + + //get optionals + UnitOfMeasure eachUom = eachUomOptional.get(); + UnitOfMeasure tableSpoonUOM = tableSpoonUomOptional.get(); + UnitOfMeasure teaspoonUOM = teaSpoonUomOptional.get(); + UnitOfMeasure dashUom = dashUOMOptional.get(); + UnitOfMeasure pintUom = pintUOMOptional.get(); + UnitOfMeasure cupsUom = cupsUOMOptional.get(); + + //Categorias + Optional americanCategoryOptional = categoryRepository.findByDescription("American"); + if(!americanCategoryOptional.isPresent()){ + throw new RuntimeException("Expected Category not found"); + } + Optional mexicanCategoryOptional = categoryRepository.findByDescription("Mexican"); + if(!mexicanCategoryOptional.isPresent()){ + throw new RuntimeException("Expected Category not found"); + } + + Category americanCategory = americanCategoryOptional.get(); + Category mexicanCategory = mexicanCategoryOptional.get(); + + //Creamos la receta + Recipe guacRecipe = new Recipe(); + guacRecipe.setDescription("Perfect Guacamole"); + guacRecipe.setPrepTime(10); + guacRecipe.setCookTime(0); + guacRecipe.setDifficulty(Difficulty.EASY); + guacRecipe.setDirections("1. Cut the avocados: Cut the avocados in half. Remove the pit. Score the inside of the avocado with a blunt knife and scoop out the flesh with a spoon. Place in a bowl\n" + + "2. Mash the avocado flesh: Using a fork, roughly mash the avocado. \n" + + "3. Add the remaining ingredients to taste: Sprinkle with salt and lime (or lemon) juice. Add the chopped onion, cilantro, black pepper, and chilis.\n" + + "4. Serve immediately\n"); + Notes guacNotes = new Notes(); + guacNotes.setRecipeNotes("Chilling tomatoes hurts their flavor.\n" + + "So, if you want to add chopped tomato to your guacamole, add it just before serving.\n" + + "Read more: https://www.simplyrecipes.com/recipes/perfect_guacamole/"); + guacRecipe.setNotes(guacNotes); + guacRecipe.addIngredient(new Ingredient("Ripe Avocados",new BigDecimal(2), eachUom)); + guacRecipe.addIngredient(new Ingredient("Kosher salt",new BigDecimal(0.5), teaspoonUOM)); + guacRecipe.addIngredient(new Ingredient("Fresh lime/lemon juice",new BigDecimal(2), tableSpoonUOM)); + guacRecipe.addIngredient(new Ingredient("Minced Red/green onion ",new BigDecimal(2), tableSpoonUOM)); + guacRecipe.addIngredient(new Ingredient("Serrano chiles, stems and seeds removed",new BigDecimal(2), eachUom)); + guacRecipe.addIngredient(new Ingredient("Cilantro",new BigDecimal(2),tableSpoonUOM)); + guacRecipe.addIngredient(new Ingredient("Freshly grated black pepper",new BigDecimal(2), dashUom)); + guacRecipe.addIngredient(new Ingredient("Ripe tomato, seeds and pulp removed",new BigDecimal(0.5), eachUom)); + + guacRecipe.getCategories().add(americanCategory); + guacRecipe.getCategories().add(mexicanCategory); + guacRecipe.setUrl("https://www.simplyrecipes.com/recipes/perfect_guacamole/"); + guacRecipe.setServings(4); + guacRecipe.setSource("Simply Recipes"); + + recipes.add(guacRecipe); + + //Tacos + Recipe tacosRecipe = new Recipe(); + tacosRecipe.setDescription("Spicy Grilled Chicken Taco"); + tacosRecipe.setCookTime(15); + tacosRecipe.setPrepTime(20); + tacosRecipe.setDifficulty(Difficulty.MODERATE); + + tacosRecipe.setDirections("1. Prepare the grill: Prepare either a gas or charcoal grill for medium-high, direct heat.\n" + + "2. Make the marinade and coat the chicken: In a large bowl, stir together the chili powder, oregano, cumin, sugar, salt, garlic and orange zest. Stir in the orange juice and olive oil to make a loose paste. Add the chicken to the bowl and toss to coat all over. Set aside.\n" + + "3. Grill the chicken: Grill the chicken for 3 to 4 minutes per side, or until a thermometer inserted into the thickest part of the meat registers 165°F. Transfer to a plate and rest for 5 minutes.\n" + + "4. Thin the sour cream with milk: Stir together the sour cream and milk to thin out the sour cream to make it easy to drizzle.\n" + + "5. Assemble the tacos: Slice the chicken into strips. On each tortilla, place a small handful of arugula. Top with chicken slices, sliced avocado, radishes, tomatoes, and onion slices. Drizzle with the thinned sour cream. Serve with lime wedges.\n" + + "6. Warm the tortillas: Place each tortilla on the grill or on a hot, dry skillet over medium-high heat. As soon as you see pockets of the air start to puff up in the tortilla, turn it with tongs and heat for a few seconds on the other side. Wrap warmed tortillas in a tea towel to keep them warm until serving.\n"); + + Notes tacoNotes = new Notes(); + tacoNotes.setRecipeNotes("Look for ancho chile powder with the Mexican ingredients at your grocery store, on buy it online. (If you can't find ancho chili powder, you replace the ancho chili, the oregano, and the cumin with 2 1/2 tablespoons regular chili powder, though the flavor won't be quite the same.)\n" + + "Read more: https://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/\n"); + tacosRecipe.setNotes(tacoNotes); + + tacosRecipe.addIngredient(new Ingredient("Ancho chilli powder", new BigDecimal(2), tableSpoonUOM)); + tacosRecipe.addIngredient(new Ingredient("Dried oregano", new BigDecimal(1), teaspoonUOM)); + tacosRecipe.addIngredient(new Ingredient("Dried Cumin", new BigDecimal(1), teaspoonUOM)); + tacosRecipe.addIngredient(new Ingredient("Salt", new BigDecimal(0.5), teaspoonUOM)); + tacosRecipe.addIngredient(new Ingredient("Corn tortillas", new BigDecimal(8), eachUom)); + tacosRecipe.addIngredient(new Ingredient("Avocado, sliced", new BigDecimal(2), eachUom)); + tacosRecipe.addIngredient(new Ingredient("Boneless Chicken thighs", new BigDecimal(6), eachUom)); + tacosRecipe.addIngredient(new Ingredient("Onion, sliced", new BigDecimal(0.25), eachUom)); + tacosRecipe.addIngredient(new Ingredient("Sour cream", new BigDecimal(0.5), cupsUom)); + tacosRecipe.addIngredient(new Ingredient("Lime/lemon", new BigDecimal(1), eachUom)); + + tacosRecipe.getCategories().add(americanCategory); + tacosRecipe.getCategories().add(mexicanCategory); + + tacosRecipe.setUrl("https://www.simplyrecipes.com/recipes/spicy_grilled_chicken_tacos/"); + tacosRecipe.setServings(6); + tacosRecipe.setSource("Simply Recipes"); + + recipes.add(tacosRecipe); + return recipes; + } +} diff --git a/src/main/java/guru/springframework/commands/CategoryCommand.java b/src/main/java/guru/springframework/commands/CategoryCommand.java new file mode 100644 index 0000000000..7263928369 --- /dev/null +++ b/src/main/java/guru/springframework/commands/CategoryCommand.java @@ -0,0 +1,13 @@ +package guru.springframework.commands; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Setter +@Getter +@NoArgsConstructor +public class CategoryCommand { + private Long id; + private String description; +} diff --git a/src/main/java/guru/springframework/commands/IngredientCommand.java b/src/main/java/guru/springframework/commands/IngredientCommand.java new file mode 100644 index 0000000000..4ff0855636 --- /dev/null +++ b/src/main/java/guru/springframework/commands/IngredientCommand.java @@ -0,0 +1,18 @@ +package guru.springframework.commands; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.math.BigDecimal; + +@Getter +@Setter +@NoArgsConstructor +public class IngredientCommand { + private Long id; + private Long recipeId; + private String description; + private BigDecimal amount; + private UnitOfMeasureCommand uom; +} diff --git a/src/main/java/guru/springframework/commands/NotesCommand.java b/src/main/java/guru/springframework/commands/NotesCommand.java new file mode 100644 index 0000000000..60fc9314b1 --- /dev/null +++ b/src/main/java/guru/springframework/commands/NotesCommand.java @@ -0,0 +1,13 @@ +package guru.springframework.commands; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class NotesCommand { + private Long id; + private String recipeNotes; +} diff --git a/src/main/java/guru/springframework/commands/RecipeCommand.java b/src/main/java/guru/springframework/commands/RecipeCommand.java new file mode 100644 index 0000000000..6558e41321 --- /dev/null +++ b/src/main/java/guru/springframework/commands/RecipeCommand.java @@ -0,0 +1,43 @@ +package guru.springframework.commands; + +import guru.springframework.domain.Difficulty; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.validator.constraints.URL; + +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.util.HashSet; +import java.util.Set; + +@Getter +@Setter +@NoArgsConstructor +public class RecipeCommand { + private Long id; + @NotBlank + @Size(min = 3, max = 255) + private String description; + @Min(1) + @Max(999) + private Integer prepTime; + @Min(1) + @Max(999) + private Integer cookTime; + @Min(1) + @Max(100) + private Integer servings; + private String source; + @URL + private String url; + @NotBlank + private String directions; + private Set ingredients = new HashSet<>(); + private Byte[] image; + private Difficulty difficulty; + private NotesCommand notes; + private Set categories = new HashSet<>(); +} diff --git a/src/main/java/guru/springframework/commands/UnitOfMeasureCommand.java b/src/main/java/guru/springframework/commands/UnitOfMeasureCommand.java new file mode 100644 index 0000000000..1e7ff68751 --- /dev/null +++ b/src/main/java/guru/springframework/commands/UnitOfMeasureCommand.java @@ -0,0 +1,13 @@ +package guru.springframework.commands; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +public class UnitOfMeasureCommand { + private Long id; + private String description; +} diff --git a/src/main/java/guru/springframework/controllers/ControllerExceptionHandler.java b/src/main/java/guru/springframework/controllers/ControllerExceptionHandler.java new file mode 100644 index 0000000000..3bbb33afda --- /dev/null +++ b/src/main/java/guru/springframework/controllers/ControllerExceptionHandler.java @@ -0,0 +1,23 @@ +package guru.springframework.controllers; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.servlet.ModelAndView; + +@Slf4j +@ControllerAdvice +public class ControllerExceptionHandler { + @ResponseStatus(HttpStatus.BAD_REQUEST) + @ExceptionHandler(NumberFormatException.class) + public ModelAndView handleNumberFormat(Exception exception) { + log.error("Handling number format exception"); + log.error(exception.getMessage()); + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("400error"); + modelAndView.addObject("exception",exception); + return modelAndView; + } +} diff --git a/src/main/java/guru/springframework/controllers/ImageController.java b/src/main/java/guru/springframework/controllers/ImageController.java new file mode 100644 index 0000000000..dc12ae70f2 --- /dev/null +++ b/src/main/java/guru/springframework/controllers/ImageController.java @@ -0,0 +1,56 @@ +package guru.springframework.controllers; + +import guru.springframework.commands.RecipeCommand; +import guru.springframework.services.ImageService; +import guru.springframework.services.RecipeService; +import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +@Controller +public class ImageController { + private final ImageService imageService; + private final RecipeService recipeService; + + public ImageController(ImageService imageService, RecipeService recipeService) { + this.imageService = imageService; + this.recipeService = recipeService; + } + @GetMapping("recipe/{id}/image") + public String showUploadForm(@PathVariable String id, Model model){ + model.addAttribute("recipe", recipeService.findCommandById(Long.valueOf(id))); + return "recipe/imageuploadform"; + } + @PostMapping("recipe/{id}/image") + public String handleImagePost(@PathVariable String id, @RequestParam("imagefile")MultipartFile file){ + imageService.saveImageFile(Long.valueOf(id),file); + return "redirect:/recipe/" + id + "/show"; + } + @GetMapping("recipe/{id}/recipeimage") + public void renderImageFromDB(@PathVariable String id, HttpServletResponse response) throws IOException { + RecipeCommand recipeCommand = recipeService.findCommandById(Long.valueOf(id)); + + if(recipeCommand.getImage() != null){ + byte[] byteArray = new byte[recipeCommand.getImage().length]; + int i = 0; + + for(Byte wrappedByte : recipeCommand.getImage()){ + byteArray[i++] = wrappedByte; + } + + response.setContentType("image/jpeg"); + InputStream is = new ByteArrayInputStream(byteArray); + IOUtils.copy(is,response.getOutputStream()); + } + } +} diff --git a/src/main/java/guru/springframework/controllers/IndexController.java b/src/main/java/guru/springframework/controllers/IndexController.java new file mode 100644 index 0000000000..41c272dbc9 --- /dev/null +++ b/src/main/java/guru/springframework/controllers/IndexController.java @@ -0,0 +1,30 @@ +package guru.springframework.controllers; + +import guru.springframework.domain.Category; +import guru.springframework.domain.UnitOfMeasure; +import guru.springframework.repositories.CategoryRepository; +import guru.springframework.repositories.UnitOfMeasureRepository; +import guru.springframework.services.RecipeService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.util.Optional; +@Slf4j +@Controller +public class IndexController { + + private final RecipeService recipeService; + + public IndexController(RecipeService recipeService) { + this.recipeService = recipeService; + } + + @RequestMapping({"","/","index"}) + public String getIndexPage(Model model){ + log.debug("Getting index page"); + model.addAttribute("recipes",recipeService.getRecipes()); + return "index"; //ligado a una pagina de inicio + } +} diff --git a/src/main/java/guru/springframework/controllers/IngredientController.java b/src/main/java/guru/springframework/controllers/IngredientController.java new file mode 100644 index 0000000000..fea770e7c9 --- /dev/null +++ b/src/main/java/guru/springframework/controllers/IngredientController.java @@ -0,0 +1,81 @@ +package guru.springframework.controllers; + +import guru.springframework.commands.IngredientCommand; +import guru.springframework.commands.RecipeCommand; +import guru.springframework.commands.UnitOfMeasureCommand; +import guru.springframework.services.IngredientService; +import guru.springframework.services.RecipeService; +import guru.springframework.services.UnitOfMeasureService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +@Slf4j +@Controller +public class IngredientController { + private final RecipeService recipeService; + private final IngredientService ingredientService; + private final UnitOfMeasureService unitOfMeasureService; + + public IngredientController(RecipeService recipeService, IngredientService ingredientService, UnitOfMeasureService unitOfMeasureService) { + this.recipeService = recipeService; + this.ingredientService = ingredientService; + this.unitOfMeasureService = unitOfMeasureService; + } + + @GetMapping("/recipe/{recipeId}/ingredients") + public String listIngredients(@PathVariable String recipeId, Model model){ + log.debug("Getting ingredient list for recipe id: "+recipeId); + + model.addAttribute("recipe",recipeService.findCommandById(Long.valueOf(recipeId))); + + return "recipe/ingredient/list"; + } + + @GetMapping("recipe/{recipeId}/ingredient/{id}/show") + public String showRecipeIngredient(@PathVariable String recipeId, @PathVariable String id, Model model){ + model.addAttribute("ingredient",ingredientService.findByRecipeIdAndIngredientId(Long.valueOf(recipeId),Long.valueOf(id))); + return "recipe/ingredient/show"; + } + + @GetMapping("recipe/{recipeId}/ingredient/new") + public String newIngredient(@PathVariable String recipeId, Model model){ + RecipeCommand recipeCommand = recipeService.findCommandById(Long.valueOf(recipeId)); + + //return back parent id + IngredientCommand ingredientCommand = new IngredientCommand(); + ingredientCommand.setRecipeId(Long.valueOf(recipeId)); + model.addAttribute("ingredient",ingredientCommand); + + //init uom + ingredientCommand.setUom(new UnitOfMeasureCommand()); + model.addAttribute("uomList",unitOfMeasureService.listAllUoms()); + return "recipe/ingredient/ingredientform"; + } + + @GetMapping("recipe/{recipeId}/ingredient/{id}/update") + public String updateRecipeIngredient(@PathVariable String recipeId, @PathVariable String id, Model model){ + model.addAttribute("ingredient",ingredientService.findByRecipeIdAndIngredientId(Long.valueOf(recipeId), Long.valueOf(id))); + model.addAttribute("uomList",unitOfMeasureService.listAllUoms()); + return "recipe/ingredient/ingredientform"; + } + + @PostMapping("recipe/{recipeId}/ingredient") + public String saveOrUpdate(@ModelAttribute IngredientCommand command){ + IngredientCommand savedCommand = ingredientService.saveIngredientCommand(command); + + log.debug("saved recipe id: " + savedCommand.getRecipeId()); + log.debug("saved ingredient id: " + savedCommand.getId()); + + return "redirect:/recipe/" + savedCommand.getRecipeId() + "/ingredient/" + savedCommand.getId() + "/show"; + } + + @GetMapping("recipe/{recipeId}/ingredient/{id}/delete") + public String deleteIngredient(@PathVariable String recipeId, @PathVariable String id){ + log.debug("deleting ingredient id: " + id); + ingredientService.deleteById(Long.valueOf(recipeId), Long.valueOf(id)); + return "redirect:/recipe/" + recipeId + "/ingredients"; + } + +} diff --git a/src/main/java/guru/springframework/controllers/RecipeController.java b/src/main/java/guru/springframework/controllers/RecipeController.java new file mode 100644 index 0000000000..92c8ac6fac --- /dev/null +++ b/src/main/java/guru/springframework/controllers/RecipeController.java @@ -0,0 +1,70 @@ +package guru.springframework.controllers; + +import guru.springframework.commands.RecipeCommand; +import guru.springframework.exceptions.NotFoundException; +import guru.springframework.services.RecipeService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.servlet.ModelAndView; + +import javax.validation.Valid; + +@Slf4j +@Controller +public class RecipeController { + private final RecipeService recipeService; + private static final String RECIPE_RECIPEFORM_URL = "recipe/recipeform"; + + public RecipeController(RecipeService recipeService) { + this.recipeService = recipeService; + } + @GetMapping("/recipe/{id}/show") + public String showById(@PathVariable String id, Model model){ + model.addAttribute("recipe",recipeService.findById(Long.valueOf(id))); + return "recipe/show"; + } + @GetMapping("recipe/new") + public String newRecipe(Model model){ + model.addAttribute("recipe", new RecipeCommand()); + + return "recipe/recipeform"; + } + @GetMapping("recipe/{id}/update") + public String updateRecipe(@PathVariable String id, Model model){ + model.addAttribute("recipe", recipeService.findCommandById(Long.valueOf(id))); + return RECIPE_RECIPEFORM_URL; + } + @PostMapping("recipe") + public String saveOrUpdate(@Valid @ModelAttribute("recipe") RecipeCommand command, BindingResult bindingResult){ + if(bindingResult.hasErrors()) { + bindingResult.getAllErrors().forEach(objectError -> { + log.debug(objectError.toString()); + }); + return RECIPE_RECIPEFORM_URL; + } + RecipeCommand savedCommand = recipeService.saveRecipeCommand(command); + return "redirect:/recipe/" + savedCommand.getId() + "/show"; + } + + @GetMapping("recipe/{id}/delete") + public String deleteById(@PathVariable String id){ + log.debug("Deleting id: " +id); + + recipeService.deleteById(Long.valueOf(id)); + return "redirect:/"; + } + @ResponseStatus(HttpStatus.NOT_FOUND) + @ExceptionHandler(NotFoundException.class) + public ModelAndView handleNotFound(Exception exception){ + log.error("Handling not found exception"); + log.error(exception.getMessage()); + ModelAndView modelAndView = new ModelAndView(); + modelAndView.setViewName("404error"); + modelAndView.addObject("exception",exception); + return modelAndView; + } +} diff --git a/src/main/java/guru/springframework/converters/CategoryCommandToCategory.java b/src/main/java/guru/springframework/converters/CategoryCommandToCategory.java new file mode 100644 index 0000000000..2cf483e911 --- /dev/null +++ b/src/main/java/guru/springframework/converters/CategoryCommandToCategory.java @@ -0,0 +1,24 @@ +package guru.springframework.converters; + +import guru.springframework.commands.CategoryCommand; +import guru.springframework.domain.Category; +import lombok.Synchronized; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +@Component +public class CategoryCommandToCategory implements Converter { + @Synchronized + @Nullable + @Override + public Category convert(CategoryCommand source){ + if(source == null){ + return null; + } + final Category category = new Category(); + category.setId(source.getId()); + category.setDescription((source.getDescription())); + return category; + } +} diff --git a/src/main/java/guru/springframework/converters/CategoryToCategoryCommand.java b/src/main/java/guru/springframework/converters/CategoryToCategoryCommand.java new file mode 100644 index 0000000000..55408cec25 --- /dev/null +++ b/src/main/java/guru/springframework/converters/CategoryToCategoryCommand.java @@ -0,0 +1,26 @@ +package guru.springframework.converters; + +import guru.springframework.commands.CategoryCommand; +import guru.springframework.domain.Category; +import lombok.Synchronized; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +@Component +public class CategoryToCategoryCommand implements Converter { + @Synchronized + @Nullable + @Override + public CategoryCommand convert(Category source){ + if(source == null){ + return null; + } + final CategoryCommand categoryCommand = new CategoryCommand(); + + categoryCommand.setId(source.getId()); + categoryCommand.setDescription(source.getDescription()); + + return categoryCommand; + } +} diff --git a/src/main/java/guru/springframework/converters/IngredientCommandToIngredient.java b/src/main/java/guru/springframework/converters/IngredientCommandToIngredient.java new file mode 100644 index 0000000000..852c878b63 --- /dev/null +++ b/src/main/java/guru/springframework/converters/IngredientCommandToIngredient.java @@ -0,0 +1,31 @@ +package guru.springframework.converters; + +import guru.springframework.commands.IngredientCommand; +import guru.springframework.domain.Ingredient; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +@Component +public class IngredientCommandToIngredient implements Converter { + private final UnitOfMeasureCommandToUnitOfMeasure uomConverter; + + public IngredientCommandToIngredient(UnitOfMeasureCommandToUnitOfMeasure uomConverter){ + this.uomConverter = uomConverter; + } + + @Nullable + @Override + public Ingredient convert(IngredientCommand source){ + if(source == null){ + return null; + } + + final Ingredient ingredient = new Ingredient(); + ingredient.setId(source.getId()); + ingredient.setAmount(source.getAmount()); + ingredient.setDescription(source.getDescription()); + ingredient.setUnitOfMeasure(uomConverter.convert(source.getUom())); + return ingredient; + } +} diff --git a/src/main/java/guru/springframework/converters/IngredientToIngredientCommand.java b/src/main/java/guru/springframework/converters/IngredientToIngredientCommand.java new file mode 100644 index 0000000000..364d9561c2 --- /dev/null +++ b/src/main/java/guru/springframework/converters/IngredientToIngredientCommand.java @@ -0,0 +1,36 @@ +package guru.springframework.converters; + +import guru.springframework.commands.IngredientCommand; +import guru.springframework.domain.Ingredient; +import lombok.Synchronized; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +@Component +public class IngredientToIngredientCommand implements Converter { + private final UnitOfMeasureToUnitOfMeasureCommand uomConverter; + + public IngredientToIngredientCommand(UnitOfMeasureToUnitOfMeasureCommand uomConverter){ + this.uomConverter = uomConverter; + } + + @Synchronized + @Nullable + @Override + public IngredientCommand convert(Ingredient ingredient){ + if(ingredient == null){ + return null; + } + + IngredientCommand ingredientCommand = new IngredientCommand(); + ingredientCommand.setId(ingredient.getId()); + if(ingredient.getRecipe() != null){ + ingredientCommand.setRecipeId(ingredient.getRecipe().getId()); + } + ingredientCommand.setAmount(ingredient.getAmount()); + ingredientCommand.setDescription(ingredient.getDescription()); + ingredientCommand.setUom(uomConverter.convert(ingredient.getUnitOfMeasure())); + return ingredientCommand; + } +} diff --git a/src/main/java/guru/springframework/converters/NotesCommandToNotes.java b/src/main/java/guru/springframework/converters/NotesCommandToNotes.java new file mode 100644 index 0000000000..fbe833a1f5 --- /dev/null +++ b/src/main/java/guru/springframework/converters/NotesCommandToNotes.java @@ -0,0 +1,25 @@ +package guru.springframework.converters; + +import guru.springframework.commands.NotesCommand; +import guru.springframework.domain.Notes; +import lombok.Synchronized; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +@Component +public class NotesCommandToNotes implements Converter { + @Synchronized + @Nullable + @Override + public Notes convert(NotesCommand source){ + if(source == null){ + return null; + } + + final Notes notes = new Notes(); + notes.setId(source.getId()); + notes.setRecipeNotes(source.getRecipeNotes()); + return notes; + } +} diff --git a/src/main/java/guru/springframework/converters/NotesToNotesCommand.java b/src/main/java/guru/springframework/converters/NotesToNotesCommand.java new file mode 100644 index 0000000000..baab40b963 --- /dev/null +++ b/src/main/java/guru/springframework/converters/NotesToNotesCommand.java @@ -0,0 +1,25 @@ +package guru.springframework.converters; + +import guru.springframework.commands.NotesCommand; +import guru.springframework.domain.Notes; +import lombok.Synchronized; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +@Component +public class NotesToNotesCommand implements Converter { + @Synchronized + @Nullable + @Override + public NotesCommand convert(Notes source){ + if(source == null){ + return null; + } + + final NotesCommand notesCommand = new NotesCommand(); + notesCommand.setId(source.getId()); + notesCommand.setRecipeNotes(source.getRecipeNotes()); + return notesCommand; + } +} diff --git a/src/main/java/guru/springframework/converters/RecipeCommandToRecipe.java b/src/main/java/guru/springframework/converters/RecipeCommandToRecipe.java new file mode 100644 index 0000000000..f7c3e2c7bc --- /dev/null +++ b/src/main/java/guru/springframework/converters/RecipeCommandToRecipe.java @@ -0,0 +1,52 @@ +package guru.springframework.converters; + +import guru.springframework.commands.RecipeCommand; +import guru.springframework.domain.Recipe; +import lombok.Synchronized; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +@Component +public class RecipeCommandToRecipe implements Converter { + private final CategoryCommandToCategory categoryConverter; + private final IngredientCommandToIngredient ingredientConverter; + private final NotesCommandToNotes notesConverter; + + public RecipeCommandToRecipe(CategoryCommandToCategory categoryConverter, IngredientCommandToIngredient ingredientConverter, NotesCommandToNotes notesConverter) { + this.categoryConverter = categoryConverter; + this.ingredientConverter = ingredientConverter; + this.notesConverter = notesConverter; + } + + @Synchronized + @Nullable + @Override + public Recipe convert(RecipeCommand source){ + if(source == null){ + return null; + } + + final Recipe recipe = new Recipe(); + recipe.setId(source.getId()); + recipe.setCookTime(source.getCookTime()); + recipe.setPrepTime(source.getPrepTime()); + recipe.setDescription(source.getDescription()); + recipe.setDifficulty(source.getDifficulty()); + recipe.setDirections(source.getDirections()); + recipe.setServings(source.getServings()); + recipe.setSource(source.getSource()); + recipe.setUrl(source.getUrl()); + recipe.setNotes(notesConverter.convert(source.getNotes())); + + if(source.getCategories() != null && source.getCategories().size() > 0){ + source.getCategories().forEach(category -> recipe.getCategories().add(categoryConverter.convert(category))); + } + + if(source.getIngredients() != null && source.getIngredients().size() > 0){ + source.getIngredients().forEach(ingredient -> recipe.getIngredients().add(ingredientConverter.convert(ingredient))); + } + + return recipe; + } +} diff --git a/src/main/java/guru/springframework/converters/RecipeToRecipeCommand.java b/src/main/java/guru/springframework/converters/RecipeToRecipeCommand.java new file mode 100644 index 0000000000..4cbd3ba93b --- /dev/null +++ b/src/main/java/guru/springframework/converters/RecipeToRecipeCommand.java @@ -0,0 +1,54 @@ +package guru.springframework.converters; + +import guru.springframework.commands.RecipeCommand; +import guru.springframework.domain.Category; +import guru.springframework.domain.Recipe; +import lombok.Synchronized; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +@Component +public class RecipeToRecipeCommand implements Converter { + private final CategoryToCategoryCommand categoryConverter; + private final IngredientToIngredientCommand ingredientConverter; + private final NotesToNotesCommand notesConverter; + + public RecipeToRecipeCommand(CategoryToCategoryCommand categoryConverter, IngredientToIngredientCommand ingredientConverter, NotesToNotesCommand notesConverter) { + this.categoryConverter = categoryConverter; + this.ingredientConverter = ingredientConverter; + this.notesConverter = notesConverter; + } + + @Synchronized + @Nullable + @Override + public RecipeCommand convert(Recipe source){ + if(source == null){ + return null; + } + + final RecipeCommand command = new RecipeCommand(); + command.setId(source.getId()); + command.setCookTime(source.getCookTime()); + command.setPrepTime(source.getPrepTime()); + command.setDescription(source.getDescription()); + command.setDifficulty(source.getDifficulty()); + command.setDirections(source.getDirections()); + command.setServings(source.getServings()); + command.setSource(source.getSource()); + command.setUrl(source.getUrl()); + command.setImage(source.getImage()); + command.setNotes(notesConverter.convert(source.getNotes())); + + if(source.getCategories() != null && source.getCategories().size() > 0){ + source.getCategories().forEach((Category category) -> command.getCategories().add(categoryConverter.convert(category))); + } + + if(source.getIngredients() != null && source.getIngredients().size() > 0){ + source.getIngredients().forEach(ingredient -> command.getIngredients().add(ingredientConverter.convert(ingredient))); + } + + return command; + } +} diff --git a/src/main/java/guru/springframework/converters/UnitOfMeasureCommandToUnitOfMeasure.java b/src/main/java/guru/springframework/converters/UnitOfMeasureCommandToUnitOfMeasure.java new file mode 100644 index 0000000000..1f3be7d08a --- /dev/null +++ b/src/main/java/guru/springframework/converters/UnitOfMeasureCommandToUnitOfMeasure.java @@ -0,0 +1,24 @@ +package guru.springframework.converters; + +import guru.springframework.commands.UnitOfMeasureCommand; +import guru.springframework.domain.UnitOfMeasure; +import lombok.Synchronized; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +@Component +public class UnitOfMeasureCommandToUnitOfMeasure implements Converter { + @Synchronized + @Nullable + @Override + public UnitOfMeasure convert(UnitOfMeasureCommand source) { + if (source == null) { + return null; + } + final UnitOfMeasure uom = new UnitOfMeasure(); + uom.setId(source.getId()); + uom.setDescription(source.getDescription()); + return uom; + } +} diff --git a/src/main/java/guru/springframework/converters/UnitOfMeasureToUnitOfMeasureCommand.java b/src/main/java/guru/springframework/converters/UnitOfMeasureToUnitOfMeasureCommand.java new file mode 100644 index 0000000000..e765fe7fd0 --- /dev/null +++ b/src/main/java/guru/springframework/converters/UnitOfMeasureToUnitOfMeasureCommand.java @@ -0,0 +1,24 @@ +package guru.springframework.converters; + +import guru.springframework.commands.UnitOfMeasureCommand; +import guru.springframework.domain.UnitOfMeasure; +import lombok.Synchronized; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; + +@Component +public class UnitOfMeasureToUnitOfMeasureCommand implements Converter { + @Synchronized + @Nullable + @Override + public UnitOfMeasureCommand convert(UnitOfMeasure unitOfMeasure){ + if(unitOfMeasure != null){ + final UnitOfMeasureCommand uomc = new UnitOfMeasureCommand(); + uomc.setId(unitOfMeasure.getId()); + uomc.setDescription(unitOfMeasure.getDescription()); + return uomc; + } + return null; + } +} diff --git a/src/main/java/guru/springframework/domain/Category.java b/src/main/java/guru/springframework/domain/Category.java new file mode 100644 index 0000000000..a093645566 --- /dev/null +++ b/src/main/java/guru/springframework/domain/Category.java @@ -0,0 +1,20 @@ +package guru.springframework.domain; + +import lombok.*; + +import javax.persistence.*; +import java.util.Set; + +@Getter +@Setter +@EqualsAndHashCode(exclude = {"recipes"}) +@Entity +public class Category { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String description; + @ManyToMany(mappedBy = "categories") + private Set recipes; + +} diff --git a/src/main/java/guru/springframework/domain/Difficulty.java b/src/main/java/guru/springframework/domain/Difficulty.java new file mode 100644 index 0000000000..13e606e127 --- /dev/null +++ b/src/main/java/guru/springframework/domain/Difficulty.java @@ -0,0 +1,5 @@ +package guru.springframework.domain; + +public enum Difficulty { + EASY, MODERATE, HARD +} diff --git a/src/main/java/guru/springframework/domain/Ingredient.java b/src/main/java/guru/springframework/domain/Ingredient.java new file mode 100644 index 0000000000..5251923a03 --- /dev/null +++ b/src/main/java/guru/springframework/domain/Ingredient.java @@ -0,0 +1,35 @@ +package guru.springframework.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.*; +import java.math.BigDecimal; +@Getter +@Setter +@EqualsAndHashCode(exclude = {"recipe"}) +@Entity +public class Ingredient { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String description; + private BigDecimal amount; + //hay que ligar a la clase Receta + @ManyToOne + private Recipe recipe; + //ligamos a la clase unitofmeasure con el comportamiento eager (siempre) + @OneToOne(fetch = FetchType.EAGER) + private UnitOfMeasure unitOfMeasure; + + public Ingredient(){ + + } + public Ingredient(String description, BigDecimal amount, UnitOfMeasure unitOfMeasure) { + this.description = description; + this.amount = amount; + this.unitOfMeasure = unitOfMeasure; + } +} diff --git a/src/main/java/guru/springframework/domain/Notes.java b/src/main/java/guru/springframework/domain/Notes.java new file mode 100644 index 0000000000..a912687bb6 --- /dev/null +++ b/src/main/java/guru/springframework/domain/Notes.java @@ -0,0 +1,25 @@ +package guru.springframework.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.*; +@Getter +@Setter +@EqualsAndHashCode(exclude = {"recipe"}) +@Entity +public class Notes { + //primary key + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + //relación con Recipe + @OneToOne + private Recipe recipe; + //hay que permitir que se acepte mas que el limite de caracteres (255) con @Lob + @Lob + private String recipeNotes; + +} diff --git a/src/main/java/guru/springframework/domain/Recipe.java b/src/main/java/guru/springframework/domain/Recipe.java new file mode 100644 index 0000000000..d3557f8b7d --- /dev/null +++ b/src/main/java/guru/springframework/domain/Recipe.java @@ -0,0 +1,53 @@ +package guru.springframework.domain; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.*; +import java.util.HashSet; +import java.util.Set; +@Getter +@Setter +@Entity +public class Recipe { + //primary key generada con la estrategia de identidad + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String description; + private Integer prepTime; + private Integer cookTime; + private Integer servings; + private String source; + private String url; + @Lob + private String directions; + //anotacion de enumeracion con valor + @Enumerated(value = EnumType.STRING) + private Difficulty difficulty; + @Lob + private Byte[] image; + //propiedad 1 a 1 con cascada lo que significa que el Owning es Recipe + @OneToOne(cascade = CascadeType.ALL) + private Notes notes; + //propiedad 1 a muchos con cascada mapeado por esta clase + @OneToMany(cascade = CascadeType.ALL, mappedBy = "recipe") + private Set ingredients = new HashSet<>(); + @ManyToMany + @JoinTable(name = "recipe_category", + joinColumns = @JoinColumn(name = "recipe_id"), + inverseJoinColumns = @JoinColumn(name = "category_id")) + private Set categories = new HashSet<>(); + public void setNotes(Notes notes) { + if(notes != null) { + this.notes = notes; + notes.setRecipe(this); + } + } + public Recipe addIngredient(Ingredient ingredient){ + ingredient.setRecipe(this); + this.ingredients.add(ingredient); + return this; + } +} diff --git a/src/main/java/guru/springframework/domain/UnitOfMeasure.java b/src/main/java/guru/springframework/domain/UnitOfMeasure.java new file mode 100644 index 0000000000..a6bfbf8095 --- /dev/null +++ b/src/main/java/guru/springframework/domain/UnitOfMeasure.java @@ -0,0 +1,16 @@ +package guru.springframework.domain; + +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.*; +@Getter +@Setter +@Entity +public class UnitOfMeasure { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String description; +} diff --git a/src/main/java/guru/springframework/exceptions/NotFoundException.java b/src/main/java/guru/springframework/exceptions/NotFoundException.java new file mode 100644 index 0000000000..230ff0e965 --- /dev/null +++ b/src/main/java/guru/springframework/exceptions/NotFoundException.java @@ -0,0 +1,17 @@ +package guru.springframework.exceptions; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.NOT_FOUND) +public class NotFoundException extends RuntimeException { + public NotFoundException(){ + super(); + } + public NotFoundException(String message) { + super(message); + } + public NotFoundException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/guru/springframework/repositories/CategoryRepository.java b/src/main/java/guru/springframework/repositories/CategoryRepository.java new file mode 100644 index 0000000000..ab7c53e194 --- /dev/null +++ b/src/main/java/guru/springframework/repositories/CategoryRepository.java @@ -0,0 +1,12 @@ +package guru.springframework.repositories; + +import guru.springframework.domain.Category; +import org.springframework.data.repository.CrudRepository; + +import java.util.Optional; + +public interface CategoryRepository extends CrudRepository { + + Optional findByDescription(String description); + +} diff --git a/src/main/java/guru/springframework/repositories/RecipeRepository.java b/src/main/java/guru/springframework/repositories/RecipeRepository.java new file mode 100644 index 0000000000..6ad1fec334 --- /dev/null +++ b/src/main/java/guru/springframework/repositories/RecipeRepository.java @@ -0,0 +1,7 @@ +package guru.springframework.repositories; + +import guru.springframework.domain.Recipe; +import org.springframework.data.repository.CrudRepository; + +public interface RecipeRepository extends CrudRepository { +} diff --git a/src/main/java/guru/springframework/repositories/UnitOfMeasureRepository.java b/src/main/java/guru/springframework/repositories/UnitOfMeasureRepository.java new file mode 100644 index 0000000000..15cb9a4046 --- /dev/null +++ b/src/main/java/guru/springframework/repositories/UnitOfMeasureRepository.java @@ -0,0 +1,10 @@ +package guru.springframework.repositories; + +import guru.springframework.domain.UnitOfMeasure; +import org.springframework.data.repository.CrudRepository; + +import java.util.Optional; + +public interface UnitOfMeasureRepository extends CrudRepository { + Optional findByDescription(String description); +} diff --git a/src/main/java/guru/springframework/services/ImageService.java b/src/main/java/guru/springframework/services/ImageService.java new file mode 100644 index 0000000000..a8682c24b2 --- /dev/null +++ b/src/main/java/guru/springframework/services/ImageService.java @@ -0,0 +1,7 @@ +package guru.springframework.services; + +import org.springframework.web.multipart.MultipartFile; + +public interface ImageService { + void saveImageFile(Long recipeId, MultipartFile file); +} diff --git a/src/main/java/guru/springframework/services/ImageServiceImpl.java b/src/main/java/guru/springframework/services/ImageServiceImpl.java new file mode 100644 index 0000000000..1b84ca0eb2 --- /dev/null +++ b/src/main/java/guru/springframework/services/ImageServiceImpl.java @@ -0,0 +1,39 @@ +package guru.springframework.services; + +import guru.springframework.domain.Recipe; +import guru.springframework.repositories.RecipeRepository; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.transaction.Transactional; +import java.io.IOException; + +@Slf4j +@Service +public class ImageServiceImpl implements ImageService{ + private final RecipeRepository recipeRepository; + + public ImageServiceImpl(RecipeRepository recipeRepository) { + this.recipeRepository = recipeRepository; + } + + @Override + @Transactional + public void saveImageFile(Long recipeId, MultipartFile file){ + try{ + Recipe recipe = recipeRepository.findById(recipeId).get(); + Byte[] byteObjects = new Byte[file.getBytes().length]; + int i = 0; + + for(byte b : file.getBytes()){ + byteObjects[i++] = b; + } + recipe.setImage(byteObjects); + recipeRepository.save(recipe); + } catch(IOException e) { + log.error("Error Occurred",e); + e.printStackTrace(); + } + } +} diff --git a/src/main/java/guru/springframework/services/IngredientService.java b/src/main/java/guru/springframework/services/IngredientService.java new file mode 100644 index 0000000000..3f24889c73 --- /dev/null +++ b/src/main/java/guru/springframework/services/IngredientService.java @@ -0,0 +1,9 @@ +package guru.springframework.services; + +import guru.springframework.commands.IngredientCommand; + +public interface IngredientService { + IngredientCommand findByRecipeIdAndIngredientId(Long recipeId, Long ingredientId); + IngredientCommand saveIngredientCommand(IngredientCommand command); + void deleteById(Long recipeId, Long idToDelete); +} diff --git a/src/main/java/guru/springframework/services/IngredientServiceImpl.java b/src/main/java/guru/springframework/services/IngredientServiceImpl.java new file mode 100644 index 0000000000..3275bbc3c5 --- /dev/null +++ b/src/main/java/guru/springframework/services/IngredientServiceImpl.java @@ -0,0 +1,127 @@ +package guru.springframework.services; + +import guru.springframework.commands.IngredientCommand; +import guru.springframework.converters.IngredientCommandToIngredient; +import guru.springframework.converters.IngredientToIngredientCommand; +import guru.springframework.domain.Ingredient; +import guru.springframework.domain.Recipe; +import guru.springframework.repositories.RecipeRepository; +import guru.springframework.repositories.UnitOfMeasureRepository; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.Optional; + +@Slf4j +@Service +public class IngredientServiceImpl implements IngredientService{ + private final IngredientToIngredientCommand ingredientToIngredientCommand; + private final IngredientCommandToIngredient ingredientCommandToIngredient; + private final RecipeRepository recipeRepository; + private final UnitOfMeasureRepository unitOfMeasureRepository; + + public IngredientServiceImpl(IngredientToIngredientCommand ingredientToIngredientCommand, IngredientCommandToIngredient ingredientCommandToIngredient, RecipeRepository recipeRepository, UnitOfMeasureRepository unitOfMeasureRepository) { + this.ingredientToIngredientCommand = ingredientToIngredientCommand; + this.ingredientCommandToIngredient = ingredientCommandToIngredient; + this.recipeRepository = recipeRepository; + this.unitOfMeasureRepository = unitOfMeasureRepository; + } + + @Override + public IngredientCommand findByRecipeIdAndIngredientId(Long recipeId, Long ingredientId){ + Optional recipeOptional = recipeRepository.findById(recipeId); + + if(!recipeOptional.isPresent()){ + log.error("recipe id not found. Id: " + recipeId); + } + + Recipe recipe = recipeOptional.get(); + + Optional ingredientCommandOptional = recipe.getIngredients().stream() + .filter(ingredient -> ingredient.getId().equals(ingredientId)) + .map( ingredient -> ingredientToIngredientCommand.convert(ingredient)).findFirst(); + + if(!ingredientCommandOptional.isPresent()){ + log.error("Ingredient id not found: " + ingredientId); + } + + return ingredientCommandOptional.get(); + } + @Override + @Transactional + public IngredientCommand saveIngredientCommand(IngredientCommand command){ + Optional recipeOptional = recipeRepository.findById(command.getRecipeId()); + + if(!recipeOptional.isPresent()){ + log.error("Recipe not found for id: " + command.getRecipeId()); + return new IngredientCommand(); + } else{ + Recipe recipe = recipeOptional.get(); + Optional ingredientOptional = recipe + .getIngredients() + .stream() + .filter(ingredient -> ingredient.getId().equals(command.getId())) + .findFirst(); + if(ingredientOptional.isPresent()){ + Ingredient ingredientFound = ingredientOptional.get(); + ingredientFound.setDescription(command.getDescription()); + ingredientFound.setAmount(command.getAmount()); + ingredientFound.setUnitOfMeasure(unitOfMeasureRepository.findById(command.getUom().getId()) + .orElseThrow(()-> new RuntimeException("UOM NOT FOUND"))); + }else{ + //agregar ingrediente nuevo + Ingredient ingredient = ingredientCommandToIngredient.convert(command); + ingredient.setRecipe(recipe); + recipe.addIngredient(ingredient); + } + + Recipe savedRecipe = recipeRepository.save(recipe); + + Optional savedIngredientOptional = savedRecipe.getIngredients().stream() + .filter(recipeIngredients -> recipeIngredients.getId().equals(command.getId())) + .findFirst(); + + //checar por descripcion + if(!savedIngredientOptional.isPresent()){ + savedIngredientOptional = savedRecipe.getIngredients().stream() + .filter(recipeIngredients -> recipeIngredients.getDescription().equals(command.getDescription())) + .filter(recipeIngredients -> recipeIngredients.getAmount().equals(command.getAmount())) + .filter(recipeIngredients -> recipeIngredients.getUnitOfMeasure().getId().equals(command.getUom().getId())) + .findFirst(); + } + + // checar fallas + return ingredientToIngredientCommand.convert(savedIngredientOptional.get()); + } + } + + @Override + public void deleteById(Long recipeId, Long idToDelete){ + log.debug("Deleting ingredient: " + recipeId + ":" + idToDelete); + + Optional recipeOptional = recipeRepository.findById(recipeId); + + if(recipeOptional.isPresent()){ + Recipe recipe = recipeOptional.get(); + log.debug("found recipe"); + + Optional ingredientOptional = recipe + .getIngredients() + .stream() + .filter(ingredient -> ingredient.getId().equals(idToDelete)) + .findFirst(); + + if(ingredientOptional.isPresent()){ + log.debug("found ingredient"); + Ingredient ingredientToDelete = ingredientOptional.get(); + ingredientToDelete.setRecipe(null); + recipe.getIngredients().remove(ingredientOptional.get()); + recipeRepository.save(recipe); + } + } else{ + log.debug("Recipe Id Not Found. Id: " + recipeId); + } + } + +} diff --git a/src/main/java/guru/springframework/services/RecipeService.java b/src/main/java/guru/springframework/services/RecipeService.java new file mode 100644 index 0000000000..41c972b5a2 --- /dev/null +++ b/src/main/java/guru/springframework/services/RecipeService.java @@ -0,0 +1,15 @@ +package guru.springframework.services; + +import guru.springframework.commands.RecipeCommand; +import guru.springframework.domain.Recipe; +import org.springframework.stereotype.Service; + +import java.util.Set; +@Service +public interface RecipeService { + Set getRecipes(); + Recipe findById(Long l); + RecipeCommand findCommandById(Long l); + RecipeCommand saveRecipeCommand(RecipeCommand command); + void deleteById(Long idToDelete); +} diff --git a/src/main/java/guru/springframework/services/RecipeServiceImpl.java b/src/main/java/guru/springframework/services/RecipeServiceImpl.java new file mode 100644 index 0000000000..9f863a20f2 --- /dev/null +++ b/src/main/java/guru/springframework/services/RecipeServiceImpl.java @@ -0,0 +1,65 @@ +package guru.springframework.services; + +import guru.springframework.commands.RecipeCommand; +import guru.springframework.converters.RecipeCommandToRecipe; +import guru.springframework.converters.RecipeToRecipeCommand; +import guru.springframework.domain.Recipe; +import guru.springframework.exceptions.NotFoundException; +import guru.springframework.repositories.RecipeRepository; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +@Slf4j +@Service +public class RecipeServiceImpl implements RecipeService{ + private final RecipeRepository recipeRepository; + private final RecipeCommandToRecipe recipeCommandToRecipe; + private final RecipeToRecipeCommand recipeToRecipeCommand; + + public RecipeServiceImpl(RecipeRepository recipeRepository, RecipeCommandToRecipe recipeCommandToRecipe, RecipeToRecipeCommand recipeToRecipeCommand) { + this.recipeRepository = recipeRepository; + this.recipeCommandToRecipe = recipeCommandToRecipe; + this.recipeToRecipeCommand = recipeToRecipeCommand; + } + + @Override + public Set getRecipes() { + log.debug("I'm in the service"); + + Set recipeSet = new HashSet<>(); + recipeRepository.findAll().iterator().forEachRemaining(recipeSet::add); + return recipeSet; + } + + @Override + public Recipe findById(Long l){ + Optional recipeOptional = recipeRepository.findById(l); + + if(!recipeOptional.isPresent()){ + throw new NotFoundException("Recipe not found for ID value : " + l.toString()); + } + return recipeOptional.get(); + } + @Override + @Transactional + public RecipeCommand findCommandById(Long l){ + return recipeToRecipeCommand.convert(findById(l)); + } + @Override + @Transactional + public RecipeCommand saveRecipeCommand(RecipeCommand command){ + Recipe detachedRecipe = recipeCommandToRecipe.convert(command); + Recipe savedRecipe = recipeRepository.save(detachedRecipe); + log.debug("Saved recipeId: "+savedRecipe.getId()); + return recipeToRecipeCommand.convert(savedRecipe); + } + + @Override + public void deleteById(Long idToDelete){ + recipeRepository.deleteById(idToDelete); + } +} diff --git a/src/main/java/guru/springframework/services/UnitOfMeasureService.java b/src/main/java/guru/springframework/services/UnitOfMeasureService.java new file mode 100644 index 0000000000..6fea70337d --- /dev/null +++ b/src/main/java/guru/springframework/services/UnitOfMeasureService.java @@ -0,0 +1,9 @@ +package guru.springframework.services; + +import guru.springframework.commands.UnitOfMeasureCommand; + +import java.util.Set; + +public interface UnitOfMeasureService { + Set listAllUoms(); +} diff --git a/src/main/java/guru/springframework/services/UnitOfMeasureServiceImpl.java b/src/main/java/guru/springframework/services/UnitOfMeasureServiceImpl.java new file mode 100644 index 0000000000..a8cc3c9c1c --- /dev/null +++ b/src/main/java/guru/springframework/services/UnitOfMeasureServiceImpl.java @@ -0,0 +1,29 @@ +package guru.springframework.services; + +import guru.springframework.commands.UnitOfMeasureCommand; +import guru.springframework.converters.UnitOfMeasureToUnitOfMeasureCommand; +import guru.springframework.repositories.UnitOfMeasureRepository; +import org.springframework.stereotype.Service; + +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +@Service +public class UnitOfMeasureServiceImpl implements UnitOfMeasureService{ + private final UnitOfMeasureRepository unitOfMeasureRepository; + private final UnitOfMeasureToUnitOfMeasureCommand unitOfMeasureToUnitOfMeasureCommand; + + public UnitOfMeasureServiceImpl(UnitOfMeasureRepository unitOfMeasureRepository, UnitOfMeasureToUnitOfMeasureCommand unitOfMeasureToUnitOfMeasureCommand) { + this.unitOfMeasureRepository = unitOfMeasureRepository; + this.unitOfMeasureToUnitOfMeasureCommand = unitOfMeasureToUnitOfMeasureCommand; + } + + @Override + public Set listAllUoms(){ + return StreamSupport.stream(unitOfMeasureRepository.findAll() + .spliterator(),false) + .map(unitOfMeasureToUnitOfMeasureCommand::convert) + .collect(Collectors.toSet()); + } +} diff --git a/src/main/resources/application-default.properties b/src/main/resources/application-default.properties new file mode 100644 index 0000000000..7fc0016312 --- /dev/null +++ b/src/main/resources/application-default.properties @@ -0,0 +1,2 @@ +spring.datasource.platform=h2 +spring.jpa.show-sql=true \ No newline at end of file diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml new file mode 100644 index 0000000000..bc9ec1caf4 --- /dev/null +++ b/src/main/resources/application-dev.yml @@ -0,0 +1,21 @@ +spring: + datasource: + url: jdbc:mysql://localhost:3306/sfg_dev ?serverTimezone=UTC + username: sfg_dev_user + password: Springboot23 + initialization-mode: always + platform: mysql + jpa: + hibernate: + ddl-auto: validate + database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + database: mysql + show-sql: true +# properties: +# javax: +# persistence: +# schema-generation: +# create-source: metadata +# scripts: +# action: create +# create-target: guru_database_create.sql \ No newline at end of file diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml new file mode 100644 index 0000000000..c5d99188fd --- /dev/null +++ b/src/main/resources/application-prod.yml @@ -0,0 +1,13 @@ +spring: + datasource: + url: jdbc:mysql://localhost:3306/sfg_prod + username: sfg_prod_user + password: Springboot23 + initialization-mode: always + platform: mysql + jpa: + hibernate: + ddl-auto: validate + database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + database: mysql + show-sql: false \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e69de29bb2..e45c5013c5 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +logging.level.guru.springframework=debug \ No newline at end of file diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 0000000000..5ff96800d5 --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,7 @@ + ________ _______ ________ ___ ________ _______ ________ ________ ________ +|\ __ \|\ ___ \ |\ ____\|\ \|\ __ \|\ ___ \ |\ __ \|\ __ \|\ __ \ +\ \ \|\ \ \ __/|\ \ \___|\ \ \ \ \|\ \ \ __/| \ \ \|\ \ \ \|\ \ \ \|\ \ + \ \ _ _\ \ \_|/_\ \ \ \ \ \ \ ____\ \ \_|/__ \ \ __ \ \ ____\ \ ____\ + \ \ \\ \\ \ \_|\ \ \ \____\ \ \ \ \___|\ \ \_|\ \ \ \ \ \ \ \ \___|\ \ \___| + \ \__\\ _\\ \_______\ \_______\ \__\ \__\ \ \_______\ \ \__\ \__\ \__\ \ \__\ + \|__|\|__|\|_______|\|_______|\|__|\|__| \|_______| \|__|\|__|\|__| \|__| diff --git a/src/main/resources/data-h2.sql b/src/main/resources/data-h2.sql new file mode 100644 index 0000000000..de968881cb --- /dev/null +++ b/src/main/resources/data-h2.sql @@ -0,0 +1,12 @@ +INSERT INTO category (description) VALUES ('American'); +INSERT INTO category (description) VALUES ('Mexican'); +INSERT INTO category (description) VALUES ('Italian'); +INSERT INTO category (description) VALUES ('Fast Food'); +INSERT INTO unit_of_measure (description) VALUES ('Teaspoon'); +INSERT INTO unit_of_measure (description) VALUES ('Tablespoon'); +INSERT INTO unit_of_measure (description) VALUES ('Cup'); +INSERT INTO unit_of_measure (description) VALUES ('Pinch'); +INSERT INTO unit_of_measure (description) VALUES ('Ounce'); +INSERT INTO unit_of_measure (description) VALUES ('Each'); +INSERT INTO unit_of_measure (description) VALUES ('Dash'); +INSERT INTO unit_of_measure (description) VALUES ('Pint'); \ No newline at end of file diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties new file mode 100644 index 0000000000..104a37c42f --- /dev/null +++ b/src/main/resources/messages.properties @@ -0,0 +1,13 @@ +#set name properties +recipe.description = Description (default) + +#Validation messages +#Order of precedence +# 1 code.objectName.fieldName +# 2 code.fieldName +# 3 code.fieldType (Java data type) +# 4 code +NotBlank.recipe.description = Description cannot be blank +Size.recipe.description = {0} must be between {2} and {1} characters long +Max.recipe.cookTime = {0} must be less than {1} +URL.recipe.url = Please provide a valid URL \ No newline at end of file diff --git a/src/main/resources/templates/400error.html b/src/main/resources/templates/400error.html new file mode 100644 index 0000000000..33d8992904 --- /dev/null +++ b/src/main/resources/templates/400error.html @@ -0,0 +1,28 @@ + + + + + Recipe Home + + + + + + + +
+
+
+

400 Bad Request

+

+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/404error.html b/src/main/resources/templates/404error.html new file mode 100644 index 0000000000..dfa99c0635 --- /dev/null +++ b/src/main/resources/templates/404error.html @@ -0,0 +1,28 @@ + + + + + Recipe Home + + + + + + + +
+
+
+

404 Not Found

+

+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000000..8f2f6eae06 --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,70 @@ + + + + + Recipe Home + + + + + + + + + +
+
+
+
+
+

My Recipes!

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDDescriptionViewUpdateDelete
123TastyView Update Delete
345SpicyView Update Delete
678SweetViewUpdateDelete
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/recipe/imageuploadform.html b/src/main/resources/templates/recipe/imageuploadform.html new file mode 100644 index 0000000000..2cd753e3af --- /dev/null +++ b/src/main/resources/templates/recipe/imageuploadform.html @@ -0,0 +1,45 @@ + + + + + Show Recipe + + + + + + + + + +
+
+
+
+
+
+

Upload a new recipe image

+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/recipe/ingredient/ingredientform.html b/src/main/resources/templates/recipe/ingredient/ingredientform.html new file mode 100644 index 0000000000..740fc354f5 --- /dev/null +++ b/src/main/resources/templates/recipe/ingredient/ingredientform.html @@ -0,0 +1,61 @@ + + + + + View Ingredient + + + + + + + +
+
+
+ +
+ +
+
+
+

Edit Ingredient Information

+
+
+ + +
+
+ + +
+ +
+ + +
+ +
+ + +
+
+
+
+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/recipe/ingredient/list.html b/src/main/resources/templates/recipe/ingredient/list.html new file mode 100644 index 0000000000..ce65ac35cb --- /dev/null +++ b/src/main/resources/templates/recipe/ingredient/list.html @@ -0,0 +1,68 @@ + + + + + List Ingredients + + + + + + + +
+
+
+
+
+
+

Ingredients

+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IDDescriptionViewUpdateDelete
123Tasty Goodnees 1ViewUpdateDelete
12333Tasty Goodnees 2ViewUpdateDelete
334Tasty Goodnees 3ViewUpdateDelete
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/recipe/ingredient/show.html b/src/main/resources/templates/recipe/ingredient/show.html new file mode 100644 index 0000000000..350eea0b89 --- /dev/null +++ b/src/main/resources/templates/recipe/ingredient/show.html @@ -0,0 +1,55 @@ + + + + + View Ingredient + + + + + + + +
+
+
+
+
+
+

Ingredient

+
+
+ +
+ + + + + + + + + + + + + + + + + + +
IDDescription
123Tasty Goodnees 1ViewUpdateDelete
334Tasty Goodness 3
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/recipe/recipeform.html b/src/main/resources/templates/recipe/recipeform.html new file mode 100644 index 0000000000..6ee4164580 --- /dev/null +++ b/src/main/resources/templates/recipe/recipeform.html @@ -0,0 +1,186 @@ + + + + + Show Recipe + + + + + + + + + +
+
+
+
+
+

Please correct Errors below

+
+ + +
+
+
+

Edit Recipe Information

+
+
+
+
+ + + +
    +
  • +
+
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+
+
+
+ + + +
    +
  • +
+
+
+
+ + + +
    +
  • +
+
+
+
+ + + +
+
+
+
+ + + +
    +
  • +
+
+
+
+ + +
+
+ + + +
    +
  • +
+
+
+
+
+
+
+
+
+
+

Ingredients

+
+
+ Edit +
+
+
+
+
+
+
    +
  • 1 Cup of milk
  • +
  • 1 Teaspoon of chocolate
  • +
  • 1 Teaspoon of Sugar +
  • +
+
+
+
+
+
+
+

Directions

+
+
+
+
+
+
+
+
+
+
+

Notes

+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ + + diff --git a/src/main/resources/templates/recipe/show.html b/src/main/resources/templates/recipe/show.html new file mode 100644 index 0000000000..d8b8a3453a --- /dev/null +++ b/src/main/resources/templates/recipe/show.html @@ -0,0 +1,155 @@ + + + + + Show Recipe + + + + + + + + +
+
+
+
+
+
+ Recipe Description Here! +
+ +
+
+
+ Categories: +
+
+
    +
  • cat one
  • +
  • cat two
  • + +
  • cat three
  • +
+
+
+ +
+
+
+
+ Prep Time: +
+
+ +

30 min

+
+
+ Difficulty: +
+
+

Easy

+
+
+
+
+ Cooktime: +
+
+

30 min

+
+
+ Servings: +
+
+

4

+
+
+
+
+ Source: +
+
+

30 min

+
+
+ URL: +
+
+

http://www.example.com

+
+
+
+
+
+
+
+
+

Ingredients

+
+
+ View +
+
+
+
+
+
+
    +
  • 1 Cup of milk
  • +
  • 1 Teaspoon of chocolate
  • + +
  • 1 Teaspoon of Sugar
  • +
+
+
+
+
+
+
+ Directions +
+
+
+
+

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum.

+
+
+
+
+
+
+ Notes +
+
+
+
+

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus, sem quam semper libero, sit amet adipiscing sem neque sed ipsum.

+
+
+
+
+
+
+
+
+ + + diff --git a/src/main/scripts/configure-mysql.sql b/src/main/scripts/configure-mysql.sql new file mode 100644 index 0000000000..7d0748efad --- /dev/null +++ b/src/main/scripts/configure-mysql.sql @@ -0,0 +1,31 @@ +## Use to run mysql db docker image, optional if youre not using a local mysqldb +## docker run --name mysqldb -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=yes -d mysql + +# connect to mysql and run as root user +#Create Databases +CREATE DATABASE sfg_dev; +CREATE DATABASE sfg_prod; + +#Create database service accounts +CREATE USER 'sfg_dev_user'@'localhost' IDENTIFIED BY 'guru'; +CREATE USER 'sfg_prod_user'@'localhost' IDENTIFIED BY 'guru'; +CREATE USER 'sfg_dev_user'@'%' IDENTIFIED BY 'guru'; +CREATE USER 'sfg_prod_user'@'%' IDENTIFIED BY 'guru'; + +#Database grants +GRANT SELECT ON sfg_dev.* to 'sfg_dev_user'@'localhost'; +GRANT INSERT ON sfg_dev.* to 'sfg_dev_user'@'localhost'; +GRANT DELETE ON sfg_dev.* to 'sfg_dev_user'@'localhost'; +GRANT UPDATE ON sfg_dev.* to 'sfg_dev_user'@'localhost'; +GRANT SELECT ON sfg_prod.* to 'sfg_prod_user'@'localhost'; +GRANT INSERT ON sfg_prod.* to 'sfg_prod_user'@'localhost'; +GRANT DELETE ON sfg_prod.* to 'sfg_prod_user'@'localhost'; +GRANT UPDATE ON sfg_prod.* to 'sfg_prod_user'@'localhost'; +GRANT SELECT ON sfg_dev.* to 'sfg_dev_user'@'%'; +GRANT INSERT ON sfg_dev.* to 'sfg_dev_user'@'%'; +GRANT DELETE ON sfg_dev.* to 'sfg_dev_user'@'%'; +GRANT UPDATE ON sfg_dev.* to 'sfg_dev_user'@'%'; +GRANT SELECT ON sfg_prod.* to 'sfg_prod_user'@'%'; +GRANT INSERT ON sfg_prod.* to 'sfg_prod_user'@'%'; +GRANT DELETE ON sfg_prod.* to 'sfg_prod_user'@'%'; +GRANT UPDATE ON sfg_prod.* to 'sfg_prod_user'@'%'; \ No newline at end of file diff --git a/src/test/java/guru/springframework/controllers/ImageControllerTest.java b/src/test/java/guru/springframework/controllers/ImageControllerTest.java new file mode 100644 index 0000000000..db46b2059a --- /dev/null +++ b/src/test/java/guru/springframework/controllers/ImageControllerTest.java @@ -0,0 +1,93 @@ +package guru.springframework.controllers; + +import guru.springframework.commands.RecipeCommand; +import guru.springframework.services.ImageService; +import guru.springframework.services.RecipeService; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.PathVariable; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.*; + +public class ImageControllerTest { + @Mock + ImageService imageService; + @Mock + RecipeService recipeService; + + ImageController controller; + MockMvc mockMvc; + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + controller = new ImageController(imageService,recipeService); + mockMvc = MockMvcBuilders.standaloneSetup(controller) + .setControllerAdvice(new ControllerExceptionHandler()) + .build(); + } + @Test + public void getImageForm() throws Exception { + RecipeCommand command = new RecipeCommand(); + command.setId(1L); + + when(recipeService.findCommandById(anyLong())).thenReturn(command); + + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/1/image")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.model().attributeExists("recipe")); + + verify(recipeService,times(1)).findCommandById(anyLong()); + } + @Test + public void handleImagePost() throws Exception { + MockMultipartFile multipartFile = + new MockMultipartFile("imagefile", "testing.txt", "text/plain", + "Spring Framework Guru".getBytes()); + + mockMvc.perform(MockMvcRequestBuilders.multipart("/recipe/1/image").file(multipartFile)) + .andExpect(MockMvcResultMatchers.status().is3xxRedirection()) + .andExpect(MockMvcResultMatchers.header().string("Location", "/recipe/1/show")); + + verify(imageService, times(1)).saveImageFile(anyLong(), any()); + } + @Test + public void renderImageFromDB() throws Exception { + RecipeCommand command = new RecipeCommand(); + command.setId(1L); + + String s = "fake image text"; + Byte[] bytesBoxed = new Byte[s.getBytes().length]; + int i = 0; + + for(byte primByte : s.getBytes()){ + bytesBoxed[i++] = primByte; + } + + command.setImage(bytesBoxed); + when(recipeService.findCommandById(anyLong())).thenReturn(command); + + MockHttpServletResponse response = mockMvc.perform(MockMvcRequestBuilders.get("/recipe/1/recipeimage")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andReturn().getResponse(); + + byte[] responseBytes = response.getContentAsByteArray(); + assertEquals(s.getBytes().length,responseBytes.length); + } + @Test + public void testGetImageNumberFormatException() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/asdf/recipeimage")) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andExpect(MockMvcResultMatchers.view().name("400error")); + } +} diff --git a/src/test/java/guru/springframework/controllers/IndexControllerTest.java b/src/test/java/guru/springframework/controllers/IndexControllerTest.java new file mode 100644 index 0000000000..a9a8b7baed --- /dev/null +++ b/src/test/java/guru/springframework/controllers/IndexControllerTest.java @@ -0,0 +1,65 @@ +package guru.springframework.controllers; + +import guru.springframework.domain.Recipe; +import guru.springframework.services.RecipeService; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.ui.Model; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +public class IndexControllerTest { + @Mock + RecipeService recipeService; + @Mock + Model model; + IndexController controller; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + controller = new IndexController(recipeService); + } + + @Test + public void testMockMVC() throws Exception{ + MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + mockMvc.perform(MockMvcRequestBuilders.get("/")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.view().name("index")); + + + } + + @Test + public void getIndexPage() throws Exception { + Set recipes =new HashSet<>(); + recipes.add(new Recipe()); + Recipe recipe = new Recipe(); + recipe.setId(1L); + recipes.add(recipe); + + when(recipeService.getRecipes()).thenReturn(recipes); + + ArgumentCaptor> argumentCaptor = ArgumentCaptor.forClass(Set.class); + + String viewName = controller.getIndexPage(model); + assertEquals("index",viewName); + verify(recipeService,times(1)).getRecipes(); + verify(model,times(1)).addAttribute(eq("recipes"),argumentCaptor.capture()); + + Set setInController = argumentCaptor.getValue(); + assertEquals(2,setInController.size()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/controllers/IngredientControllerTest.java b/src/test/java/guru/springframework/controllers/IngredientControllerTest.java new file mode 100644 index 0000000000..19df76d1c7 --- /dev/null +++ b/src/test/java/guru/springframework/controllers/IngredientControllerTest.java @@ -0,0 +1,124 @@ +package guru.springframework.controllers; + +import guru.springframework.commands.IngredientCommand; +import guru.springframework.commands.RecipeCommand; +import guru.springframework.services.IngredientService; +import guru.springframework.services.RecipeService; +import guru.springframework.services.UnitOfMeasureService; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; + +import java.util.HashSet; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.*; + +public class IngredientControllerTest { + @Mock + IngredientService ingredientService; + @Mock + UnitOfMeasureService unitOfMeasureService; + @Mock + RecipeService recipeService; + IngredientController controller; + MockMvc mockMvc; + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + controller = new IngredientController(recipeService,ingredientService,unitOfMeasureService); + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Test + public void testListIngredients() throws Exception { + RecipeCommand recipeCommand = new RecipeCommand(); + when(recipeService.findCommandById(anyLong())).thenReturn(recipeCommand); + + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/1/ingredients")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.view().name("recipe/ingredient/list")) + .andExpect(MockMvcResultMatchers.model().attributeExists("recipe")); + + verify(recipeService,times(1)).findCommandById(anyLong()); + } + + @Test + public void testShowIngredient() throws Exception{ + IngredientCommand ingredientCommand = new IngredientCommand(); + + when(ingredientService.findByRecipeIdAndIngredientId(anyLong(),anyLong())).thenReturn(ingredientCommand); + + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/1/ingredient/2/show")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.view().name("recipe/ingredient/show")) + .andExpect(MockMvcResultMatchers.model().attributeExists("ingredient")); + } + + @Test + public void testNewIngredientForm() throws Exception { + RecipeCommand recipeCommand = new RecipeCommand(); + recipeCommand.setId(1L); + + when(recipeService.findCommandById(anyLong())).thenReturn(recipeCommand); + when(unitOfMeasureService.listAllUoms()).thenReturn(new HashSet<>()); + + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/1/ingredient/new")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.view().name("recipe/ingredient/ingredientform")) + .andExpect(MockMvcResultMatchers.model().attributeExists("ingredient")) + .andExpect(MockMvcResultMatchers.model().attributeExists("uomList")); + + verify(recipeService, times(1)).findCommandById(anyLong()); + } + + @Test + public void testUpdateIngredientForm() throws Exception { + IngredientCommand ingredientCommand = new IngredientCommand(); + + when(ingredientService.findByRecipeIdAndIngredientId(anyLong(),anyLong())).thenReturn(ingredientCommand); + when(unitOfMeasureService.listAllUoms()).thenReturn(new HashSet<>()); + + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/1/ingredient/2/update")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.view().name("recipe/ingredient/ingredientform")) + .andExpect(MockMvcResultMatchers.model().attributeExists("ingredient")) + .andExpect(MockMvcResultMatchers.model().attributeExists("uomList")); + } + + @Test + public void testSaveOrUpdate() throws Exception{ + IngredientCommand command = new IngredientCommand(); + command.setId(3L); + command.setRecipeId(2L); + + when(ingredientService.saveIngredientCommand(any())).thenReturn(command); + + mockMvc.perform(MockMvcRequestBuilders.post("/recipe/2/ingredient") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .param("id","") + .param("description","some string") + ) + .andExpect(MockMvcResultMatchers.status().is3xxRedirection()) + .andExpect(MockMvcResultMatchers.view().name("redirect:/recipe/2/ingredient/3/show")); + + } + + @Test + public void testDeleteIngredient() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/2/ingredient/3/delete")) + .andExpect(MockMvcResultMatchers.status().is3xxRedirection()) + .andExpect(MockMvcResultMatchers.view().name("redirect:/recipe/2/ingredients")); + + verify(ingredientService,times(1)).deleteById(anyLong(),anyLong()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/controllers/RecipeControllerTest.java b/src/test/java/guru/springframework/controllers/RecipeControllerTest.java new file mode 100644 index 0000000000..adab36d09f --- /dev/null +++ b/src/test/java/guru/springframework/controllers/RecipeControllerTest.java @@ -0,0 +1,128 @@ +package guru.springframework.controllers; + +import guru.springframework.commands.RecipeCommand; +import guru.springframework.domain.Recipe; +import guru.springframework.exceptions.NotFoundException; +import guru.springframework.services.RecipeService; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +public class RecipeControllerTest { + @Mock + RecipeService recipeService; + RecipeController recipeController; + + MockMvc mockMvc; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + recipeController = new RecipeController(recipeService); + mockMvc = MockMvcBuilders.standaloneSetup(recipeController) + .setControllerAdvice(new ControllerExceptionHandler()) + .build(); + } + + @Test + public void testGetRecipe() throws Exception { + Recipe recipe = new Recipe(); + recipe.setId(1L); + + when(recipeService.findById(anyLong())).thenReturn(recipe); + + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/1/show")) + .andExpect(status().isOk()) + .andExpect(view().name("recipe/show")) + .andExpect(model().attributeExists("recipe")); + } + @Test + public void testGetRecipeNotFound() throws Exception { + when(recipeService.findById(anyLong())).thenThrow(NotFoundException.class); + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/1/show")) + .andExpect(status().isNotFound()) + .andExpect(view().name("404error")); + } + @Test + public void testNumberFormat() throws Exception { + when(recipeService.findById(anyLong())).thenThrow(NumberFormatException.class); + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/asdf/show")) + .andExpect(status().isBadRequest()) + .andExpect(view().name("400error")); + } + @Test + public void testGetNewRecipeForm() throws Exception { + RecipeCommand command = new RecipeCommand(); + + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/new")) + .andExpect(status().isOk()) + .andExpect(view().name("recipe/recipeform")) + .andExpect(model().attributeExists("recipe")); + } + + @Test + public void testPostNewRecipeForm() throws Exception { + RecipeCommand command = new RecipeCommand(); + command.setId(2L); + + when(recipeService.saveRecipeCommand(any())).thenReturn(command); + + mockMvc.perform(post("/recipe") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .param("id", "") + .param("description", "some string") + .param("directions", "some directions") + ) + .andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/recipe/2/show")); + } + @Test + public void testPostNewRecipeFormValidationFail() throws Exception { + RecipeCommand command = new RecipeCommand(); + command.setId(2L); + + when(recipeService.saveRecipeCommand(any())).thenReturn(command); + + mockMvc.perform(post("/recipe") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .param("id", "") + .param("cookTime","3000") + ) + .andExpect(status().isOk()) + .andExpect(model().attributeExists("recipe")) + .andExpect(view().name("recipe/recipeform")); + } + @Test + public void testGetUpdateView() throws Exception { + RecipeCommand command = new RecipeCommand(); + command.setId(2L); + + when(recipeService.findCommandById(anyLong())).thenReturn(command); + + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/1/update")) + .andExpect(status().isOk()) + .andExpect(view().name("recipe/recipeform")) + .andExpect(model().attributeExists("recipe")); + } + + @Test + public void testDeleteAction() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.get("/recipe/1/delete")) + .andExpect(status().is3xxRedirection()) + .andExpect(view().name("redirect:/")); + + verify(recipeService,times(1)).deleteById(anyLong()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/converters/CategoryCommandToCategoryTest.java b/src/test/java/guru/springframework/converters/CategoryCommandToCategoryTest.java new file mode 100644 index 0000000000..fb16d689f8 --- /dev/null +++ b/src/test/java/guru/springframework/converters/CategoryCommandToCategoryTest.java @@ -0,0 +1,41 @@ +package guru.springframework.converters; + +import guru.springframework.commands.CategoryCommand; +import guru.springframework.domain.Category; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class CategoryCommandToCategoryTest { + public static final Long idValue = 1L; + public static final String description = "description"; + CategoryCommandToCategory converter; + + @Before + public void setUp() throws Exception { + converter = new CategoryCommandToCategory(); + } + + @Test + public void testNullObject() throws Exception { + assertNull(converter.convert(null)); + } + + @Test + public void testEmptyObject() throws Exception { + assertNotNull(converter.convert(new CategoryCommand())); + } + + @Test + public void convert() throws Exception { + CategoryCommand categoryCommand = new CategoryCommand(); + categoryCommand.setId(idValue); + categoryCommand.setDescription(description); + + Category category = converter.convert(categoryCommand); + + assertEquals(idValue,category.getId()); + assertEquals(description,category.getDescription()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/converters/CategoryToCategoryCommandTest.java b/src/test/java/guru/springframework/converters/CategoryToCategoryCommandTest.java new file mode 100644 index 0000000000..b465e52633 --- /dev/null +++ b/src/test/java/guru/springframework/converters/CategoryToCategoryCommandTest.java @@ -0,0 +1,40 @@ +package guru.springframework.converters; + +import guru.springframework.commands.CategoryCommand; +import guru.springframework.domain.Category; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class CategoryToCategoryCommandTest { + public static final Long idValue = 1L; + public static final String description = "description"; + CategoryToCategoryCommand converter; + @Before + public void setUp() throws Exception { + converter = new CategoryToCategoryCommand(); + } + + @Test + public void testNullObject() throws Exception { + assertNull(converter.convert(null)); + } + + @Test + public void testEmptyObject() throws Exception { + assertNotNull(converter.convert(new Category())); + } + + @Test + public void convert() throws Exception { + Category category = new Category(); + category.setId(idValue); + category.setDescription(description); + + CategoryCommand categoryCommand = converter.convert(category); + + assertEquals(idValue,categoryCommand.getId()); + assertEquals(description,categoryCommand.getDescription()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/converters/IngredientCommandToIngredientTest.java b/src/test/java/guru/springframework/converters/IngredientCommandToIngredientTest.java new file mode 100644 index 0000000000..9295f3e0dc --- /dev/null +++ b/src/test/java/guru/springframework/converters/IngredientCommandToIngredientTest.java @@ -0,0 +1,73 @@ +package guru.springframework.converters; + +import guru.springframework.commands.IngredientCommand; +import guru.springframework.commands.UnitOfMeasureCommand; +import guru.springframework.domain.Ingredient; +import guru.springframework.domain.Recipe; +import org.junit.Before; +import org.junit.Test; + +import java.math.BigDecimal; + +import static org.junit.Assert.*; + +public class IngredientCommandToIngredientTest { + public static final Recipe recipe = new Recipe(); + public static final BigDecimal amount = new BigDecimal("1"); + public static final String description = "Cheeseburguer"; + public static final Long idValue = 1L; + public static final Long uomId = 2L; + IngredientCommandToIngredient converter; + + @Before + public void setUp() throws Exception { + converter = new IngredientCommandToIngredient(new UnitOfMeasureCommandToUnitOfMeasure()); + } + + @Test + public void testNullObject() throws Exception { + assertNull(converter.convert(null)); + } + + @Test + public void testEmptyObject() throws Exception { + assertNotNull(converter.convert(new IngredientCommand())); + } + + @Test + public void convert() throws Exception { + IngredientCommand command = new IngredientCommand(); + command.setId(idValue); + command.setAmount(amount); + command.setDescription(description); + UnitOfMeasureCommand unitOfMeasureCommand = new UnitOfMeasureCommand(); + unitOfMeasureCommand.setId(uomId); + command.setUom(unitOfMeasureCommand); + + Ingredient ingredient = converter.convert(command); + + assertNotNull(ingredient); + assertNotNull(ingredient.getUnitOfMeasure()); + assertEquals(idValue,ingredient.getId()); + assertEquals(amount,ingredient.getAmount()); + assertEquals(description,ingredient.getDescription()); + assertEquals(uomId,ingredient.getUnitOfMeasure().getId()); + } + + @Test + public void convertWithNullUOM() throws Exception { + IngredientCommand command = new IngredientCommand(); + command.setId(idValue); + command.setAmount(amount); + command.setDescription(description); + UnitOfMeasureCommand unitOfMeasureCommand = new UnitOfMeasureCommand(); + + Ingredient ingredient = converter.convert(command); + + assertNotNull(ingredient); + assertNull(ingredient.getUnitOfMeasure()); + assertEquals(idValue,ingredient.getId()); + assertEquals(amount,ingredient.getAmount()); + assertEquals(description,ingredient.getDescription()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/converters/IngredientToIngredientCommandTest.java b/src/test/java/guru/springframework/converters/IngredientToIngredientCommandTest.java new file mode 100644 index 0000000000..2c59ad0ac2 --- /dev/null +++ b/src/test/java/guru/springframework/converters/IngredientToIngredientCommandTest.java @@ -0,0 +1,71 @@ +package guru.springframework.converters; + +import guru.springframework.commands.IngredientCommand; +import guru.springframework.domain.Ingredient; +import guru.springframework.domain.Recipe; +import guru.springframework.domain.UnitOfMeasure; +import org.junit.Before; +import org.junit.Test; + +import java.math.BigDecimal; + +import static org.junit.Assert.*; + +public class IngredientToIngredientCommandTest { + public static final Recipe recipe = new Recipe(); + public static final BigDecimal amount = new BigDecimal("1"); + public static final String description = "description"; + public static final Long uomID = 2L; + public static final Long idValue = 1L; + IngredientToIngredientCommand converter; + + @Before + public void setUp() throws Exception { + converter = new IngredientToIngredientCommand(new UnitOfMeasureToUnitOfMeasureCommand()); + } + + @Test + public void testNullObject() throws Exception { + assertNull(converter.convert(null)); + } + + @Test + public void testEmptyObject() throws Exception { + assertNotNull(converter.convert(new Ingredient())); + } + + @Test + public void testConvertWithUOM() throws Exception { + Ingredient ingredient = new Ingredient(); + ingredient.setId(idValue); + ingredient.setAmount(amount); + ingredient.setDescription(description); + UnitOfMeasure uom = new UnitOfMeasure(); + uom.setId(uomID); + ingredient.setUnitOfMeasure(uom); + + IngredientCommand ingredientCommand = converter.convert(ingredient); + + assertEquals(idValue,ingredientCommand.getId()); + assertNotNull(ingredientCommand.getUom()); + assertEquals(uomID,ingredientCommand.getUom().getId()); + assertEquals(amount,ingredientCommand.getAmount()); + assertEquals(description,ingredientCommand.getDescription()); + } + + @Test + public void testConvertNullUOM() throws Exception { + Ingredient ingredient = new Ingredient(); + ingredient.setId(idValue); + ingredient.setAmount(amount); + ingredient.setDescription(description); + ingredient.setUnitOfMeasure(null); + + IngredientCommand ingredientCommand = converter.convert(ingredient); + + assertEquals(idValue,ingredientCommand.getId()); + assertNull(ingredientCommand.getUom()); + assertEquals(amount,ingredientCommand.getAmount()); + assertEquals(description,ingredientCommand.getDescription()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/converters/NotesCommandToNotesTest.java b/src/test/java/guru/springframework/converters/NotesCommandToNotesTest.java new file mode 100644 index 0000000000..9b998f64eb --- /dev/null +++ b/src/test/java/guru/springframework/converters/NotesCommandToNotesTest.java @@ -0,0 +1,41 @@ +package guru.springframework.converters; + +import guru.springframework.commands.NotesCommand; +import guru.springframework.domain.Notes; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class NotesCommandToNotesTest { + private static final Long idValue = 1L; + public static final String recipeNotes = "Notes"; + NotesCommandToNotes converter; + @Before + public void setUp() throws Exception { + converter = new NotesCommandToNotes(); + } + + @Test + public void testNullObject() throws Exception { + assertNull(converter.convert(null)); + } + + @Test + public void testEmptyObject() throws Exception { + assertNotNull(converter.convert(new NotesCommand())); + } + + @Test + public void convert() { + NotesCommand notesCommand = new NotesCommand(); + notesCommand.setId(idValue); + notesCommand.setRecipeNotes(recipeNotes); + + Notes notes = converter.convert(notesCommand); + + assertNotNull(notes); + assertEquals(idValue,notes.getId()); + assertEquals(recipeNotes,notes.getRecipeNotes()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/converters/NotesToNotesCommandTest.java b/src/test/java/guru/springframework/converters/NotesToNotesCommandTest.java new file mode 100644 index 0000000000..6676f96d47 --- /dev/null +++ b/src/test/java/guru/springframework/converters/NotesToNotesCommandTest.java @@ -0,0 +1,40 @@ +package guru.springframework.converters; + +import guru.springframework.commands.NotesCommand; +import guru.springframework.domain.Notes; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class NotesToNotesCommandTest { + private static final Long idValue = 1L; + private static final String recipeNotes = "Notes"; + NotesToNotesCommand converter; + @Before + public void setUp() throws Exception { + converter = new NotesToNotesCommand(); + } + + @Test + public void testNullObject() throws Exception { + assertNull(converter.convert(null)); + } + + @Test + public void testEmptyObject() throws Exception { + assertNotNull(converter.convert(new Notes())); + } + + @Test + public void convert() throws Exception { + Notes notes = new Notes(); + notes.setId(idValue); + notes.setRecipeNotes(recipeNotes); + + NotesCommand notesCommand = converter.convert(notes); + + assertEquals(idValue,notesCommand.getId()); + assertEquals(recipeNotes,notesCommand.getRecipeNotes()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/converters/RecipeCommandToRecipeTest.java b/src/test/java/guru/springframework/converters/RecipeCommandToRecipeTest.java new file mode 100644 index 0000000000..773a60f032 --- /dev/null +++ b/src/test/java/guru/springframework/converters/RecipeCommandToRecipeTest.java @@ -0,0 +1,97 @@ +package guru.springframework.converters; + +import guru.springframework.commands.CategoryCommand; +import guru.springframework.commands.IngredientCommand; +import guru.springframework.commands.NotesCommand; +import guru.springframework.commands.RecipeCommand; +import guru.springframework.domain.Difficulty; +import guru.springframework.domain.Recipe; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class RecipeCommandToRecipeTest { + public static final Long recipeid = 1L; + public static final Integer cookTime = Integer.valueOf("5"); + public static final Integer prepTime = Integer.valueOf("7"); + public static final String description = "My Recipe"; + public static final String directions = "Directions"; + public static final Difficulty difficulty = Difficulty.EASY; + public static final Integer servings = Integer.valueOf("3"); + public static final String source = "Source"; + public static final String url = "Some url"; + public static final Long catid1 = 1L; + public static final Long catid2 = 2L; + public static final Long ingred1 = 3L; + public static final Long ingred2 = 4L; + public static final Long notesId = 9L; + RecipeCommandToRecipe converter; + @Before + public void setUp() throws Exception { + converter = new RecipeCommandToRecipe(new CategoryCommandToCategory(),new IngredientCommandToIngredient(new UnitOfMeasureCommandToUnitOfMeasure()),new NotesCommandToNotes()); + } + + @Test + public void testNullObject() throws Exception { + assertNull(converter.convert(null)); + } + + @Test + public void testEmptyObject() throws Exception { + assertNotNull(converter.convert(new RecipeCommand())); + } + + @Test + public void convert() throws Exception{ + RecipeCommand recipeCommand = new RecipeCommand(); + recipeCommand.setId(recipeid); + recipeCommand.setCookTime(cookTime); + recipeCommand.setPrepTime(prepTime); + recipeCommand.setDescription(description); + recipeCommand.setDirections(directions); + recipeCommand.setDifficulty(difficulty); + recipeCommand.setServings(servings); + recipeCommand.setSource(source); + recipeCommand.setUrl(url); + + NotesCommand notes = new NotesCommand(); + notes.setId(notesId); + recipeCommand.setNotes(notes); + + CategoryCommand category = new CategoryCommand(); + category.setId(catid1); + + CategoryCommand category2 = new CategoryCommand(); + category2.setId(catid2); + + IngredientCommand ingredient = new IngredientCommand(); + ingredient.setId(ingred1); + + IngredientCommand ingredient2 = new IngredientCommand(); + ingredient2.setId(ingred2); + + recipeCommand.getCategories().add(category); + recipeCommand.getCategories().add(category2); + + recipeCommand.getIngredients().add(ingredient); + recipeCommand.getIngredients().add(ingredient2); + + Recipe recipe = converter.convert(recipeCommand); + + assertNotNull(recipe); + assertEquals(recipeid,recipe.getId()); + assertEquals(cookTime,recipe.getCookTime()); + assertEquals(prepTime,recipe.getPrepTime()); + assertEquals(description,recipe.getDescription()); + assertEquals(directions,recipe.getDirections()); + assertEquals(difficulty,recipe.getDifficulty()); + assertEquals(servings,recipe.getServings()); + assertEquals(source,recipe.getSource()); + assertEquals(url,recipe.getUrl()); + assertEquals(notesId,recipe.getNotes().getId()); + assertEquals(2,recipe.getCategories().size()); + assertEquals(2,recipe.getIngredients().size()); + + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/converters/RecipeToRecipeCommandTest.java b/src/test/java/guru/springframework/converters/RecipeToRecipeCommandTest.java new file mode 100644 index 0000000000..9df99ce065 --- /dev/null +++ b/src/test/java/guru/springframework/converters/RecipeToRecipeCommandTest.java @@ -0,0 +1,93 @@ +package guru.springframework.converters; + +import guru.springframework.commands.RecipeCommand; +import guru.springframework.domain.*; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class RecipeToRecipeCommandTest { + public static final Long recipeid = 1L; + public static final Integer cookTime = Integer.valueOf("5"); + public static final Integer prepTime = Integer.valueOf("7"); + public static final String description = "My Recipe"; + public static final String directions = "Directions"; + public static final Difficulty difficulty = Difficulty.EASY; + public static final Integer servings = Integer.valueOf("3"); + public static final String source = "Source"; + public static final String url = "Some url"; + public static final Long catId1 = 1L; + public static final Long catId2 = 2L; + public static final Long ingred1 = 3L; + public static final Long ingred2 = 4L; + public static final Long notesId = 9L; + RecipeToRecipeCommand converter; + + @Before + public void setUp() throws Exception { + converter = new RecipeToRecipeCommand(new CategoryToCategoryCommand(),new IngredientToIngredientCommand(new UnitOfMeasureToUnitOfMeasureCommand()),new NotesToNotesCommand()); + } + + @Test + public void testNullObject() throws Exception { + assertNull(converter.convert(null)); + } + + @Test + public void testEmptyObject() throws Exception{ + assertNotNull(converter.convert(new Recipe())); + } + + @Test + public void convert() throws Exception{ + Recipe recipe = new Recipe(); + recipe.setId(recipeid); + recipe.setCookTime(cookTime); + recipe.setPrepTime(prepTime); + recipe.setDescription(description); + recipe.setDirections(directions); + recipe.setDifficulty(difficulty); + recipe.setServings(servings); + recipe.setSource(source); + recipe.setUrl(url); + + Notes notes = new Notes(); + notes.setId(notesId); + recipe.setNotes(notes); + + Category category = new Category(); + category.setId(catId1); + + Category category2 = new Category(); + category2.setId(catId2); + + Ingredient ingredient = new Ingredient(); + ingredient.setId(ingred1); + + Ingredient ingredient2 = new Ingredient(); + ingredient2.setId(ingred2); + + recipe.getCategories().add(category); + recipe.getCategories().add(category2); + + recipe.getIngredients().add(ingredient); + recipe.getIngredients().add(ingredient2); + + RecipeCommand command = converter.convert(recipe); + + assertNotNull(command); + assertEquals(recipeid,command.getId()); + assertEquals(cookTime,command.getCookTime()); + assertEquals(prepTime, command.getPrepTime()); + assertEquals(description,command.getDescription()); + assertEquals(difficulty,command.getDifficulty()); + assertEquals(directions,command.getDirections()); + assertEquals(servings,command.getServings()); + assertEquals(source,command.getSource()); + assertEquals(url,command.getUrl()); + assertEquals(notesId,command.getNotes().getId()); + assertEquals(2,command.getCategories().size()); + assertEquals(2,command.getIngredients().size()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/converters/UnitOfMeasureCommandToUnitOfMeasureTest.java b/src/test/java/guru/springframework/converters/UnitOfMeasureCommandToUnitOfMeasureTest.java new file mode 100644 index 0000000000..b351170f9c --- /dev/null +++ b/src/test/java/guru/springframework/converters/UnitOfMeasureCommandToUnitOfMeasureTest.java @@ -0,0 +1,41 @@ +package guru.springframework.converters; + +import guru.springframework.commands.UnitOfMeasureCommand; +import guru.springframework.domain.UnitOfMeasure; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class UnitOfMeasureCommandToUnitOfMeasureTest { + private static final String description = "Description"; + private static final Long longVal = 1L; + UnitOfMeasureCommandToUnitOfMeasure converter; + + @Before + public void setUp() throws Exception { + converter = new UnitOfMeasureCommandToUnitOfMeasure(); + } + + @Test + public void testNullParameter() throws Exception { + assertNull(converter.convert(null)); + } + + @Test + public void testEmptyObject() throws Exception { + assertNotNull(converter.convert(new UnitOfMeasureCommand())); + } + + @Test + public void convert() throws Exception { + UnitOfMeasureCommand command = new UnitOfMeasureCommand(); + command.setId(longVal); + command.setDescription(description); + + UnitOfMeasure uom = converter.convert(command); + assertNotNull(uom); + assertEquals(longVal,uom.getId()); + assertEquals(description,uom.getDescription()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/converters/UnitOfMeasureToUnitOfMeasureCommandTest.java b/src/test/java/guru/springframework/converters/UnitOfMeasureToUnitOfMeasureCommandTest.java new file mode 100644 index 0000000000..ce7a1546a3 --- /dev/null +++ b/src/test/java/guru/springframework/converters/UnitOfMeasureToUnitOfMeasureCommandTest.java @@ -0,0 +1,39 @@ +package guru.springframework.converters; + +import guru.springframework.commands.UnitOfMeasureCommand; +import guru.springframework.domain.UnitOfMeasure; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class UnitOfMeasureToUnitOfMeasureCommandTest { + public static final Long idValue = 1L; + public static final String description = "description"; + UnitOfMeasureToUnitOfMeasureCommand converter; + @Before + public void setUp() throws Exception { + converter = new UnitOfMeasureToUnitOfMeasureCommand(); + } + + @Test + public void testNullParameter() throws Exception { + assertNull(converter.convert(null)); + } + + @Test + public void testEmptyObject() throws Exception { + assertNotNull(converter.convert(new UnitOfMeasure())); + } + + @Test + public void convert() { + UnitOfMeasure uom = new UnitOfMeasure(); + uom.setId(idValue); + uom.setDescription(description); + + UnitOfMeasureCommand command = converter.convert(uom); + assertEquals(idValue,command.getId()); + assertEquals(description,command.getDescription()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/domain/CategoryTest.java b/src/test/java/guru/springframework/domain/CategoryTest.java new file mode 100644 index 0000000000..c63db5bab2 --- /dev/null +++ b/src/test/java/guru/springframework/domain/CategoryTest.java @@ -0,0 +1,31 @@ +package guru.springframework.domain; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class CategoryTest { + Category category; + + //setup + @Before + public void setUp(){ + category = new Category(); + } + + @Test + public void getId() { + Long idValue = 4L; + category.setId(idValue); + assertEquals(idValue,category.getId()); + } + + @Test + public void getDescription() { + } + + @Test + public void getRecipes() { + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/repositories/UnitOfMeasureRepositoryIT.java b/src/test/java/guru/springframework/repositories/UnitOfMeasureRepositoryIT.java new file mode 100644 index 0000000000..97b009efb5 --- /dev/null +++ b/src/test/java/guru/springframework/repositories/UnitOfMeasureRepositoryIT.java @@ -0,0 +1,28 @@ +package guru.springframework.repositories; + +import guru.springframework.domain.UnitOfMeasure; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.Optional; + +import static org.junit.Assert.*; +@RunWith(SpringRunner.class) +@DataJpaTest +public class UnitOfMeasureRepositoryIT { + @Autowired + UnitOfMeasureRepository unitOfMeasureRepository; + @Before + public void setUp() throws Exception { + } + + @Test + public void findByDescription() throws Exception{ + Optional uomOptional = unitOfMeasureRepository.findByDescription("Teaspoon"); + assertEquals("Teaspoon", uomOptional.get().getDescription()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/services/ImageServiceImplTest.java b/src/test/java/guru/springframework/services/ImageServiceImplTest.java new file mode 100644 index 0000000000..c9830de7e4 --- /dev/null +++ b/src/test/java/guru/springframework/services/ImageServiceImplTest.java @@ -0,0 +1,46 @@ +package guru.springframework.services; + +import guru.springframework.domain.Recipe; +import guru.springframework.repositories.RecipeRepository; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; + +public class ImageServiceImplTest { + @Mock + RecipeRepository recipeRepository; + ImageService imageService; + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + imageService = new ImageServiceImpl(recipeRepository); + } + @Test + public void saveImageFile() throws Exception { + Long id = 1L; + MultipartFile multipartFile = new MockMultipartFile("imagefile","testing.txt","text/plain","Spring Framework Guru".getBytes()); + + Recipe recipe = new Recipe(); + recipe.setId(id); + Optional recipeOptional = Optional.of(recipe); + + when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); + ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Recipe.class); + + imageService.saveImageFile(id,multipartFile); + + verify(recipeRepository,times(1)).save(argumentCaptor.capture()); + Recipe savedRecipe = argumentCaptor.getValue(); + assertEquals(multipartFile.getBytes().length,savedRecipe.getImage().length); + } +} diff --git a/src/test/java/guru/springframework/services/IngredientServiceImplTest.java b/src/test/java/guru/springframework/services/IngredientServiceImplTest.java new file mode 100644 index 0000000000..81ca9d6814 --- /dev/null +++ b/src/test/java/guru/springframework/services/IngredientServiceImplTest.java @@ -0,0 +1,122 @@ +package guru.springframework.services; + +import guru.springframework.commands.IngredientCommand; +import guru.springframework.converters.IngredientCommandToIngredient; +import guru.springframework.converters.IngredientToIngredientCommand; +import guru.springframework.converters.UnitOfMeasureCommandToUnitOfMeasure; +import guru.springframework.converters.UnitOfMeasureToUnitOfMeasureCommand; +import guru.springframework.domain.Ingredient; +import guru.springframework.domain.Recipe; +import guru.springframework.repositories.RecipeRepository; +import guru.springframework.repositories.UnitOfMeasureRepository; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.*; + +public class IngredientServiceImplTest { + private final IngredientToIngredientCommand ingredientToIngredientCommand; + private final IngredientCommandToIngredient ingredientCommandToIngredient; + + @Mock + RecipeRepository recipeRepository; + @Mock + UnitOfMeasureRepository unitOfMeasureRepository; + IngredientService ingredientService; + + public IngredientServiceImplTest(){ + this.ingredientToIngredientCommand = new IngredientToIngredientCommand(new UnitOfMeasureToUnitOfMeasureCommand()); + this.ingredientCommandToIngredient = new IngredientCommandToIngredient(new UnitOfMeasureCommandToUnitOfMeasure()); + } + @Before + public void setUp() throws Exception{ + MockitoAnnotations.initMocks(this); + ingredientService = new IngredientServiceImpl(ingredientToIngredientCommand, ingredientCommandToIngredient, recipeRepository, unitOfMeasureRepository); + } + + @Test + public void findByRecipeIdAndId() throws Exception{ + + } + @Test + public void findByRecipeIdAndReceipeIdHappyPath() throws Exception { + //given + Recipe recipe = new Recipe(); + recipe.setId(1L); + + Ingredient ingredient1 = new Ingredient(); + ingredient1.setId(1L); + + Ingredient ingredient2 = new Ingredient(); + ingredient2.setId(1L); + + Ingredient ingredient3 = new Ingredient(); + ingredient3.setId(3L); + + recipe.addIngredient(ingredient1); + recipe.addIngredient(ingredient2); + recipe.addIngredient(ingredient3); + Optional recipeOptional = Optional.of(recipe); + + when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); + + //then + IngredientCommand ingredientCommand = ingredientService.findByRecipeIdAndIngredientId(1L, 3L); + + //when + assertEquals(Long.valueOf(3L), ingredientCommand.getId()); + assertEquals(Long.valueOf(1L), ingredientCommand.getRecipeId()); + verify(recipeRepository, times(1)).findById(anyLong()); + } + + + @Test + public void testSaveRecipeCommand() throws Exception { + //given + IngredientCommand command = new IngredientCommand(); + command.setId(3L); + command.setRecipeId(2L); + + Optional recipeOptional = Optional.of(new Recipe()); + + Recipe savedRecipe = new Recipe(); + savedRecipe.addIngredient(new Ingredient()); + savedRecipe.getIngredients().iterator().next().setId(3L); + + when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); + when(recipeRepository.save(any())).thenReturn(savedRecipe); + + //when + IngredientCommand savedCommand = ingredientService.saveIngredientCommand(command); + + //then + assertEquals(Long.valueOf(3L), savedCommand.getId()); + verify(recipeRepository, times(1)).findById(anyLong()); + verify(recipeRepository, times(1)).save(any(Recipe.class)); + } + + @Test + public void testDeleteById() throws Exception { + Recipe recipe = new Recipe(); + Ingredient ingredient = new Ingredient(); + ingredient.setId(3L); + recipe.addIngredient(ingredient); + ingredient.setRecipe(recipe); + Optional recipeOptional = Optional.of(recipe); + + when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); + + ingredientService.deleteById(1L,3L); + + verify(recipeRepository,times(1)).findById(anyLong()); + verify(recipeRepository,times(1)).save(any(Recipe.class)); + } +} diff --git a/src/test/java/guru/springframework/services/RecipeServiceImplTest.java b/src/test/java/guru/springframework/services/RecipeServiceImplTest.java new file mode 100644 index 0000000000..bf1b716db8 --- /dev/null +++ b/src/test/java/guru/springframework/services/RecipeServiceImplTest.java @@ -0,0 +1,79 @@ +package guru.springframework.services; + +import guru.springframework.converters.RecipeCommandToRecipe; +import guru.springframework.converters.RecipeToRecipeCommand; +import guru.springframework.domain.Recipe; +import guru.springframework.exceptions.NotFoundException; +import guru.springframework.repositories.RecipeRepository; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +public class RecipeServiceImplTest { + RecipeServiceImpl recipeService; + @Mock + RecipeRepository recipeRepository; + + @Mock + RecipeToRecipeCommand recipeToRecipeCommand; + + @Mock + RecipeCommandToRecipe recipeCommandToRecipe; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + recipeService = new RecipeServiceImpl(recipeRepository,recipeCommandToRecipe, recipeToRecipeCommand); + } + + @Test + public void getRecipeByIdTest() throws Exception { + Recipe recipe = new Recipe(); + recipe.setId(1L); + Optional recipeOptional = Optional.of(recipe); + + when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); + + Recipe recipeReturned = recipeService.findById(1L); + + assertNotNull("Null recipe returned",recipeReturned); + verify(recipeRepository,times(1)).findById(anyLong()); + verify(recipeRepository,never()).findAll(); + } + @Test(expected = NotFoundException.class) + public void getRecipeByIdTestNotFound() throws Exception { + Optional recipeOptional = Optional.empty(); + when(recipeRepository.findById(anyLong())).thenReturn(recipeOptional); + Recipe recipeReturned = recipeService.findById(1L); + } + @Test + public void getRecipesTest() throws Exception { + Recipe recipe = new Recipe(); + HashSet recipesData = new HashSet<>(); + recipesData.add(recipe); + + when(recipeService.getRecipes()).thenReturn(recipesData); + + Set recipes = recipeService.getRecipes(); + assertEquals(recipes.size(),1); + verify(recipeRepository,times(1)).findAll(); + verify(recipeRepository,never()).findById(anyLong()); + } + + @Test + public void testDeleteById() throws Exception { + Long idToDelete = Long.valueOf(2L); + recipeService.deleteById(idToDelete); + + verify(recipeRepository,times(1)).deleteById(anyLong()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/services/RecipeServiceTest.java b/src/test/java/guru/springframework/services/RecipeServiceTest.java new file mode 100644 index 0000000000..df47c35f1a --- /dev/null +++ b/src/test/java/guru/springframework/services/RecipeServiceTest.java @@ -0,0 +1,57 @@ +package guru.springframework.services; + +import guru.springframework.commands.RecipeCommand; +import guru.springframework.converters.RecipeCommandToRecipe; +import guru.springframework.converters.RecipeToRecipeCommand; +import guru.springframework.domain.Recipe; +import guru.springframework.repositories.RecipeRepository; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import static org.junit.Assert.assertEquals; + + +/** + * Created by jt on 6/21/17. + */ +@RunWith(SpringRunner.class) +@SpringBootTest +public class RecipeServiceTest{ + + public static final String NEW_DESCRIPTION = "New Description"; + + @Autowired + RecipeService recipeService; + + @Autowired + RecipeRepository recipeRepository; + + @Autowired + RecipeCommandToRecipe recipeCommandToRecipe; + + @Autowired + RecipeToRecipeCommand recipeToRecipeCommand; + + @Transactional + @Test + public void testSaveOfDescription() throws Exception { + //given + Iterable recipes = recipeRepository.findAll(); + Recipe testRecipe = recipes.iterator().next(); + RecipeCommand testRecipeCommand = recipeToRecipeCommand.convert(testRecipe); + + //when + testRecipeCommand.setDescription(NEW_DESCRIPTION); + RecipeCommand savedRecipeCommand = recipeService.saveRecipeCommand(testRecipeCommand); + + //then + assertEquals(NEW_DESCRIPTION, savedRecipeCommand.getDescription()); + assertEquals(testRecipe.getId(), savedRecipeCommand.getId()); + assertEquals(testRecipe.getCategories().size(), savedRecipeCommand.getCategories().size()); + assertEquals(testRecipe.getIngredients().size(), savedRecipeCommand.getIngredients().size()); + } +} \ No newline at end of file diff --git a/src/test/java/guru/springframework/services/UnitOfMeasureServiceImplTest.java b/src/test/java/guru/springframework/services/UnitOfMeasureServiceImplTest.java new file mode 100644 index 0000000000..2b9de9530d --- /dev/null +++ b/src/test/java/guru/springframework/services/UnitOfMeasureServiceImplTest.java @@ -0,0 +1,47 @@ +package guru.springframework.services; + +import guru.springframework.commands.UnitOfMeasureCommand; +import guru.springframework.converters.UnitOfMeasureToUnitOfMeasureCommand; +import guru.springframework.domain.UnitOfMeasure; +import guru.springframework.repositories.UnitOfMeasureRepository; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.HashSet; +import java.util.Set; + +import static junit.framework.TestCase.assertEquals; +import static org.mockito.Mockito.*; + +public class UnitOfMeasureServiceImplTest { + UnitOfMeasureToUnitOfMeasureCommand unitOfMeasureToUnitOfMeasureCommand = new UnitOfMeasureToUnitOfMeasureCommand(); + UnitOfMeasureService service; + @Mock + UnitOfMeasureRepository unitOfMeasureRepository; + @Before + public void setUp() throws Exception{ + MockitoAnnotations.initMocks(this); + service = new UnitOfMeasureServiceImpl(unitOfMeasureRepository,unitOfMeasureToUnitOfMeasureCommand); + } + + @Test + public void listAllUoms() throws Exception{ + Set unitOfMeasures = new HashSet<>(); + UnitOfMeasure uom1 = new UnitOfMeasure(); + uom1.setId(1L); + unitOfMeasures.add(uom1); + + UnitOfMeasure uom2 = new UnitOfMeasure(); + uom2.setId(2L); + unitOfMeasures.add(uom2); + + when(unitOfMeasureRepository.findAll()).thenReturn(unitOfMeasures); + + Set commands = service.listAllUoms(); + + assertEquals(2,commands.size()); + verify(unitOfMeasureRepository,times(1)).findAll(); + } +}