From 82bf485d1e502f940ba856cf55f058b193f1fd6f Mon Sep 17 00:00:00 2001 From: Robert Goldmann <deadlocker@gmx.de> Date: Sat, 10 Mar 2018 17:21:31 +0100 Subject: [PATCH] #291 - improve input validation; ftl variables are now accessible without model --- .../controller/CategoryController.java | 35 +++++++------------ .../validators/CategoryValidator.java | 4 +-- src/main/resources/languages/_de.properties | 2 +- src/main/resources/languages/_en.properties | 2 +- .../templates/categories/categories.ftl | 8 ++--- .../templates/categories/newCategory.ftl | 23 ++++++------ src/main/resources/templates/validation.ftl | 8 +++++ 7 files changed, 38 insertions(+), 44 deletions(-) create mode 100644 src/main/resources/templates/validation.ftl diff --git a/src/main/java/de/deadlocker8/budgetmaster/controller/CategoryController.java b/src/main/java/de/deadlocker8/budgetmaster/controller/CategoryController.java index aa85bf70e..ef86b19b1 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/controller/CategoryController.java +++ b/src/main/java/de/deadlocker8/budgetmaster/controller/CategoryController.java @@ -1,27 +1,21 @@ package de.deadlocker8.budgetmaster.controller; -import de.deadlocker8.budgetmaster.Validators.CategoryValidator; import de.deadlocker8.budgetmaster.entities.Category; import de.deadlocker8.budgetmaster.entities.CategoryType; import de.deadlocker8.budgetmaster.repositories.CategoryRepository; -import de.deadlocker8.budgetmaster.utils.*; -import freemarker.ext.beans.BeansWrapper; -import freemarker.template.TemplateHashModel; +import de.deadlocker8.budgetmaster.utils.Colors; +import de.deadlocker8.budgetmaster.utils.Helpers; +import de.deadlocker8.budgetmaster.utils.ResourceNotFoundException; +import de.deadlocker8.budgetmaster.validators.CategoryValidator; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; +import org.springframework.ui.Model; import org.springframework.validation.BindingResult; -import org.springframework.validation.ObjectError; -import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import tools.ConvertTo; -import tools.Localization; - -import java.util.ArrayList; @Controller @@ -32,14 +26,14 @@ public class CategoryController extends BaseController @RequestMapping("/categories") - public String index(@ModelAttribute("model") ModelMap model) + public String index(Model model) { model.addAttribute("categories", categoryRepository.findAllByOrderByNameAsc()); return "categories/categories"; } @RequestMapping("/categories/{ID}/requestDelete") - public String requestDeleteCategory(@ModelAttribute("model") ModelMap model, @PathVariable("ID") Integer ID) + public String requestDeleteCategory(Model model, @PathVariable("ID") Integer ID) { if(!isDeletable(ID)) { @@ -53,7 +47,7 @@ public class CategoryController extends BaseController } @RequestMapping("/categories/{ID}/delete") - public String deleteCategory(@ModelAttribute("model") ModelMap model, @PathVariable("ID") Integer ID) + public String deleteCategory(Model model, @PathVariable("ID") Integer ID) { if(isDeletable(ID)) { @@ -70,7 +64,7 @@ public class CategoryController extends BaseController } @RequestMapping("/categories/newCategory") - public String newCategory(@ModelAttribute("model") ModelMap model) + public String newCategory(Model model) { //TODO: add color picker for custom colors @@ -82,7 +76,7 @@ public class CategoryController extends BaseController } @RequestMapping("/categories/{ID}/edit") - public String editCategory(@ModelAttribute("model") ModelMap model, @PathVariable("ID") Integer ID) + public String editCategory(Model model, @PathVariable("ID") Integer ID) { Category category = categoryRepository.findOne(ID); if(category == null) @@ -104,20 +98,15 @@ public class CategoryController extends BaseController } @RequestMapping(value = "/categories/newCategory", method = RequestMethod.POST) - public String post(@ModelAttribute("model") ModelMap model, @ModelAttribute("NewCategory") Category category, BindingResult bindingResult) + public String post(Model model, @ModelAttribute("NewCategory") Category category, BindingResult bindingResult) { CategoryValidator userValidator = new CategoryValidator(); userValidator.validate(category, bindingResult); if(bindingResult.hasErrors()) { - ArrayList<Notification> notifications = new ArrayList<>(); - for(ObjectError error : bindingResult.getAllErrors()) - { - notifications.add(new Notification(NotificationLevel.WARNING, null, Localization.getString(error.getCode()))); - } + model.addAttribute("error", bindingResult); - model.addAttribute("notifications", notifications); if(Helpers.getCategoryColorList().contains(category.getColor())) { model.addAttribute("customColor", "#FFFFFF"); diff --git a/src/main/java/de/deadlocker8/budgetmaster/validators/CategoryValidator.java b/src/main/java/de/deadlocker8/budgetmaster/validators/CategoryValidator.java index 3a9c3db98..a7272ae90 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/validators/CategoryValidator.java +++ b/src/main/java/de/deadlocker8/budgetmaster/validators/CategoryValidator.java @@ -1,4 +1,4 @@ -package de.deadlocker8.budgetmaster.Validators; +package de.deadlocker8.budgetmaster.validators; import de.deadlocker8.budgetmaster.entities.Category; import de.deadlocker8.budgetmaster.utils.Strings; @@ -19,4 +19,4 @@ public class CategoryValidator implements Validator ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", Strings.WARNING_EMPTY_CATEGORY_NAME); ValidationUtils.rejectIfEmptyOrWhitespace(errors, "color", Strings.WARNING_EMPTY_CATEGORY_COLOR); } -} +} \ No newline at end of file diff --git a/src/main/resources/languages/_de.properties b/src/main/resources/languages/_de.properties index 2e20b7dab..0751b4ea5 100644 --- a/src/main/resources/languages/_de.properties +++ b/src/main/resources/languages/_de.properties @@ -179,7 +179,7 @@ warning.integer.width.in.pixels=Nur ganzahlige Werte sind f warning.empty.height.in.pixels=Bitte gib eine H�he in Pixeln an. warning.integer.height.in.pixels=Nur ganzahlige Werte sind f�r das Feld H�he erlaubt. warning.empty.savepath.chart=W�hle einen Speicherort f�r das Diagramm aus. -warning.empty.category.name=Das Feld f�r den Namen darf nicht leer sein. +warning.empty.category.name=Bitte gib einen Namen ein. warning.empty.category.color=Die Kategoriefarbe darf nicht leer sein. warning.empty.payment.name=Das Feld f�r den Namen darf nicht leer sein. warning.name.character.limit.reached.45=Der Name darf maximal 45 Zeichen lang sein. diff --git a/src/main/resources/languages/_en.properties b/src/main/resources/languages/_en.properties index 46285c6a6..c9ad1a60d 100644 --- a/src/main/resources/languages/_en.properties +++ b/src/main/resources/languages/_en.properties @@ -179,7 +179,7 @@ warning.integer.width.in.pixels=Only integer values are allowed for the width fi warning.empty.height.in.pixels=Please enter a height in pixels. warning.integer.height.in.pixels=Only integer values are allowed for the height field. warning.empty.savepath.chart=Please select a location where you want to save the chart. -warning.empty.category.name=The field for the name can not be empty. +warning.empty.category.name=Please insert a name. warning.empty.category.color=The category color should not be empty. warning.empty.payment.name=The field for the name can not be empty. warning.name.character.limit.reached.45=The name must not exceed 45 characters in length. diff --git a/src/main/resources/templates/categories/categories.ftl b/src/main/resources/templates/categories/categories.ftl index e403d22ef..2cc321165 100644 --- a/src/main/resources/templates/categories/categories.ftl +++ b/src/main/resources/templates/categories/categories.ftl @@ -21,7 +21,7 @@ <br> <div class="container"> <table class="bordered"> - <#list model["categories"] as category> + <#list categories as category> <tr> <td> <div class="category-circle" style="background-color: ${category.color}"> @@ -43,16 +43,16 @@ </div> </div> - <#if model["currentCategory"]??> + <#if currentCategory??> <!-- confirm delete modal --> <div id="modalConfirmDelete" class="modal"> <div class="modal-content"> <h4>Kategorie löschen</h4> - <p>Möchtest du die Kategorie "${model["currentCategory"].name}" wirklich löschen?</p> + <p>Möchtest du die Kategorie "${currentCategory.name}" wirklich löschen?</p> </div> <div class="modal-footer"> <a href="#" class="modal-action modal-close waves-effect waves-red btn-flat ">Abbrechen</a> - <a href="/categories/${model["currentCategory"].ID}/delete" class="modal-action modal-close waves-effect waves-green btn-flat ">Löschen</a> + <a href="/categories/${currentCategory.ID}/delete" class="modal-action modal-close waves-effect waves-green btn-flat ">Löschen</a> </div> </div> </#if> diff --git a/src/main/resources/templates/categories/newCategory.ftl b/src/main/resources/templates/categories/newCategory.ftl index 80300ae91..77671928b 100644 --- a/src/main/resources/templates/categories/newCategory.ftl +++ b/src/main/resources/templates/categories/newCategory.ftl @@ -13,38 +13,39 @@ <div class="card main-card"> <div class="container"> <div class="section center-align"> - <div class="grey-text text-darken-4 headline"><#if model["category"].getID()??>${locale.getString("title.category.edit")}<#else>${locale.getString("title.category.new")}</#if></div> + <div class="grey-text text-darken-4 headline"><#if category.getID()??>${locale.getString("title.category.edit")}<#else>${locale.getString("title.category.new")}</#if></div> </div> </div> <div class="container"> + <#import "../validation.ftl" as validation> <form name="NewCategory" action="/categories/newCategory" method="post"> - <input type="hidden" name="ID" value="<#if model["category"].getID()??>${model["category"].getID()}</#if>"> + <input type="hidden" name="ID" value="<#if category.getID()??>${category.getID()}</#if>"> <div class="row"> <div class="input-field col s12 m12 l8 offset-l2"> - <input id="category-name" type="text" name="name" value="<#if model["category"].getName()??>${model["category"].getName()}</#if>"> + <input id="category-name" type="text" name="name" <@validation.validation "name"/> value="<#if category.getName()??>${category.getName()}</#if>"> <label for="category-name">${locale.getString("category.new.label.name")}</label> </div> </div> - <input type="hidden" name="color" id="categoryColor" value="${model["category"].getColor()}"> + <input type="hidden" name="color" id="categoryColor" value="${category.getColor()}"> <#list categoryColors as color> <#if color?counter == 1 || color?counter == 7 || color?counter == 13> <div class="row"> <div class="col s2 m1 offset-m3 no-padding"> - <div class="category-color <#if color == model["category"].getColor()>category-color-active</#if>" style="background-color: ${color}"></div> + <div class="category-color <#if color == category.getColor()>category-color-active</#if>" style="background-color: ${color}"></div> </div> <#else> <div class="col s2 m1 no-padding"> - <div class="category-color <#if color == model["category"].getColor()>category-color-active</#if>" style="background-color: ${color}"></div> + <div class="category-color <#if color == category.getColor()>category-color-active</#if>" style="background-color: ${color}"></div> </div> </#if> <#if color?counter == 6 || color?counter == 12> </div> </#if> - </#list>- + </#list> <#--add custom color picker--> <div class="col s2 m1 no-padding"> - <div class="category-color <#if model["customColor"] == model["category"].getColor()>category-color-active</#if>" style="background-color: ${model["customColor"]}"> + <div class="category-color <#if customColor == category.getColor()>category-color-active</#if>" style="background-color: ${customColor}"> + </div> </div> @@ -81,11 +82,7 @@ </div> </main> - <!-- notification modal --> - <#import "../notification.ftl" as notification> - <@notification.notification/> - - <!-- Scripts--> + <!-- Scripts--> <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script> <script src="/js/main.js"></script> diff --git a/src/main/resources/templates/validation.ftl b/src/main/resources/templates/validation.ftl new file mode 100644 index 000000000..47c87e531 --- /dev/null +++ b/src/main/resources/templates/validation.ftl @@ -0,0 +1,8 @@ +<#macro validation fieldName classes=""> + <#assign locale = localization["tools.Localization"]> + <#if error?? && error.hasFieldErrors(fieldName)> + class="tooltipped invalid ${classes}" data-position="bottom" data-delay="50" data-tooltip="${locale.getString(error.getFieldError(fieldName).getCode())}" + <#else> + class="validate ${classes}" + </#if> +</#macro> \ No newline at end of file -- GitLab