= Финална имплементација на случаи на употреба == Корисникот пополнува форма за додавање на нов рецепт Најавен корисник се навигира кон страницата за листање на рецепти [[Image(cookCraft1A.jpg, height=450, width=900)]] Корисникот го клика копчето за додавање на рецепт и е пренасочен кон страница со форма за пополување на информации за рецептот [[Image(cookCraft2.png, height=450, width=900)]] По пополнување на потребните информации корисникот го кликнува копчето за поденување на формата. [[Image(cookCraft3.png, height=450, width=900)]] ** При испраќање на апликацијата преку POST барање најпрво преку jwt токенот се пребарува мејлот на корисникот. Потоа се прават некои основни проверки пред да се додаде апликацијата во базата ** {{{ @PostMapping("/recipes/add") public ResponseEntity addRecipeApplication( @RequestHeader("Authorization") String tokenHeader, @RequestBody RecipeApplicationDTO recipeApplicationDTO ) { String token = tokenHeader.substring(7); String email = jwtUtil.extractEmail(token); if (email == null) { return new ResponseEntity<>("Error finding user", HttpStatus.BAD_REQUEST); } if (recipeApplicationDTO.getRecipeName() == null || recipeApplicationDTO.getRecipeName().isEmpty()) { return new ResponseEntity<>("Recipe name is required", HttpStatus.BAD_REQUEST); } if (recipeApplicationDTO.getIngredients() == null || recipeApplicationDTO.getIngredients().isEmpty()) { return new ResponseEntity<>("Ingredients are required", HttpStatus.BAD_REQUEST); } recipeService.addRecipeApplication(recipeApplicationDTO); return new ResponseEntity<>(HttpStatus.OK); } }}} ** Во сервисниот дел апликацијата само се пренесува до последниот слој. ** {{{ @Override public void addRecipeApplication(RecipeApplicationDTO recipeApplicationDTO) { recipeDAO.addRecipeApplication(recipeApplicationDTO); } }}} ** Во последниот слој се додава целиот рецепт во база и се превзема неговото id. Тоа id после тоа се користи за да се додадат состојките во посебна релациона база. ** {{{ @Override public void addRecipeApplication(RecipeApplicationDTO recipeApplicationDTO) { String sql = "INSERT INTO recipe_application " + "(recipe_name, description, category, origin, meal_thumb, video_url) " + "VALUES (?, ?, ?, ?, ?, ?) RETURNING id"; Integer recipeId = jdbcTemplate.queryForObject(sql, new Object[] { recipeApplicationDTO.getRecipeName(), recipeApplicationDTO.getRecipeDesc(), recipeApplicationDTO.getRecipeCategory(), recipeApplicationDTO.getRecipeOrigin(), recipeApplicationDTO.getRecipeMealThumb(), recipeApplicationDTO.getRecipeVideoURL() }, Integer.class); if (recipeId == null) { throw new IllegalStateException("Failed to retrieve generated id for the recipe."); } recipeApplicationDTO.getIngredients().forEach(ingredient -> { jdbcTemplate.update("INSERT INTO recipe_application_ingredients (ingredient, dose, recipe_id) VALUES (?, ?, ?)", ingredient.getIngredient(), ingredient.getDose(), recipeId); }); } }}} == Администраторот проверува поднесени рецепти Администраторот се наоѓа на администраторската страница [[Image(cookCraft4.png, height=570, width=600)]] Администраторот селектира одреден рецепт и му се прикажува податоци за рецептот [[Image(cookCraft5.png, height=570, width=650)]] ** Листањето на сите апликации за нови рецепти се прави така што се прави GET барање до backend делот од апликацијата на патеката /admin/recipeapplications и како додатни параметри се праќаат page и size доколку администраторот претходно веќе започнал со листање на апликациите. Првото нешто што се прави во оваа функција е се иницијализира нова инстанца од интерфејсот Pageable и таа инстаца се праќа во тековната функција за да се превземат апликациите. Се превземаат рецептите преку query, се ставаат во листа и се праќаат назад до front-end делот од апликацијата. ** {{{ @GetMapping("/admin/recipeapplications") public ResponseEntity> getRecipeApplication( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "4") int size ) { Pageable pageable = PageRequest.of(page, size); Page recipeApplications = recipeService.findAllRecipeApplications(pageable); return new ResponseEntity<>(recipeApplications, HttpStatus.OK); } }}} ** Истата инстанца од интерфејсот Pageable се препраќа до полседниот слој. ** {{{ @Override public Page findAllRecipeApplications(Pageable pageable) { return recipeDAO.findAllRecipeApplications(pageable); } }}} ** Во последниот дел се прави sql query за селектирање на рецепти со лимит и offset за да се усогласи со потребната страница која ја бара администраторот. Исто така претходно се превзема и целосниот број на апликации ** {{{ @Override public Page findAllRecipeApplications(Pageable pageable) { String sql = "SELECT ra.id AS recipe_id, ra.recipe_name, ra.description, ra.category, ra.origin, ra.meal_thumb, ra.video_url, " + "rai.ingredient, rai.dose " + "FROM recipe_application ra " + "LEFT JOIN recipe_application_ingredients rai ON ra.id = rai.recipe_id " + "ORDER BY ra.id " + "LIMIT ? OFFSET ?"; Integer count = jdbcTemplate.queryForObject("SELECT COUNT(*) FROM recipe_application", Integer.class); RecipeApplicationRowMapper rowMapper = new RecipeApplicationRowMapper(); jdbcTemplate.query(sql, new Object[]{pageable.getPageSize(), pageable.getOffset()}, rowMapper); RecipeApplicationDTO recipe = rowMapper.getFinalRecipe(); List recipeApplications = new ArrayList<>(); if (recipe != null) { recipeApplications.add(recipe); } return new PageImpl<>(recipeApplications, pageable, count != null ? count : 0); } }}} == Најава преку Google === Ненајавен корисник Ненајавениот корисник го кликнува копчето за најава преку google профил, го селектира посакуваниот профил и се логира. [[Image(cookCraftLoginA.jpg)]] == Корисникот добива мејл кога доставувач ќе му ја прифати нарачката.