diff --git a/src/main/java/ru/mystamps/web/controller/CategoryController.java b/src/main/java/ru/mystamps/web/controller/CategoryController.java index 2cf23f6d92..b450f2d996 100644 --- a/src/main/java/ru/mystamps/web/controller/CategoryController.java +++ b/src/main/java/ru/mystamps/web/controller/CategoryController.java @@ -24,7 +24,6 @@ import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; -import org.springframework.beans.propertyeditors.StringTrimmerEditor; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -43,6 +42,7 @@ import ru.mystamps.web.Url; import ru.mystamps.web.controller.converter.annotation.Category; import ru.mystamps.web.controller.converter.annotation.CurrentUser; +import ru.mystamps.web.controller.editor.ReplaceRepeatingSpacesEditor; import ru.mystamps.web.dao.dto.LinkEntityDto; import ru.mystamps.web.dao.dto.SeriesInfoDto; import ru.mystamps.web.dao.dto.UrlEntityDto; @@ -62,7 +62,9 @@ public class CategoryController { @InitBinder("addCategoryForm") protected void initBinder(WebDataBinder binder) { - StringTrimmerEditor editor = new StringTrimmerEditor(false); + // CheckStyle: ignore LineLength for next 1 line + // We can't use StringTrimmerEditor here because "only one single registered custom editor per property path is supported". + ReplaceRepeatingSpacesEditor editor = new ReplaceRepeatingSpacesEditor(true); binder.registerCustomEditor(String.class, "name", editor); binder.registerCustomEditor(String.class, "nameRu", editor); } diff --git a/src/main/java/ru/mystamps/web/controller/editor/ReplaceRepeatingSpacesEditor.java b/src/main/java/ru/mystamps/web/controller/editor/ReplaceRepeatingSpacesEditor.java new file mode 100644 index 0000000000..2d450e6ca5 --- /dev/null +++ b/src/main/java/ru/mystamps/web/controller/editor/ReplaceRepeatingSpacesEditor.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009-2016 Slava Semushin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package ru.mystamps.web.controller.editor; + +import java.beans.PropertyEditorSupport; +import java.util.regex.Pattern; + +import lombok.RequiredArgsConstructor; + +/** + * @author Maxim Shestakov + */ +@RequiredArgsConstructor +public class ReplaceRepeatingSpacesEditor extends PropertyEditorSupport { + private static final Pattern REPEATING_SPACES = Pattern.compile("[ ]{2,}"); + private final boolean performTrimming; + + @Override + public void setAsText(String name) throws IllegalArgumentException { + String text = name; + + if (performTrimming) { + text = name.trim(); + } + + if (text.contains(" ")) { + text = REPEATING_SPACES.matcher(text).replaceAll(" "); + } + + setValue(text); + } + +} diff --git a/src/main/java/ru/mystamps/web/model/AddCategoryForm.java b/src/main/java/ru/mystamps/web/model/AddCategoryForm.java index f6d2a43c61..c32ef08e8f 100644 --- a/src/main/java/ru/mystamps/web/model/AddCategoryForm.java +++ b/src/main/java/ru/mystamps/web/model/AddCategoryForm.java @@ -34,6 +34,7 @@ import static ru.mystamps.web.validation.ValidationRules.CATEGORY_NAME_MAX_LENGTH; import static ru.mystamps.web.validation.ValidationRules.CATEGORY_NAME_MIN_LENGTH; import static ru.mystamps.web.validation.ValidationRules.CATEGORY_NAME_NO_HYPHEN_REGEXP; +import static ru.mystamps.web.validation.ValidationRules.CATEGORY_NAME_NO_REPEATING_HYPHENS_REGEXP; import static ru.mystamps.web.validation.ValidationRules.CATEGORY_NAME_RU_REGEXP; @Getter @@ -44,7 +45,8 @@ Group.Level2.class, Group.Level3.class, Group.Level4.class, - Group.Level5.class + Group.Level5.class, + Group.Level6.class }) public class AddCategoryForm implements AddCategoryDto { @@ -67,13 +69,18 @@ public class AddCategoryForm implements AddCategoryDto { message = "{category-name-en.invalid}", groups = Group.Level3.class ), + @Pattern( + regexp = CATEGORY_NAME_NO_REPEATING_HYPHENS_REGEXP, + message = "{value.repeating_hyphen}", + groups = Group.Level4.class + ), @Pattern( regexp = CATEGORY_NAME_NO_HYPHEN_REGEXP, message = "{value.hyphen}", - groups = Group.Level4.class + groups = Group.Level5.class ) }) - @UniqueCategoryName(lang = Lang.EN, groups = Group.Level5.class) + @UniqueCategoryName(lang = Lang.EN, groups = Group.Level6.class) private String name; @NotEmpty(groups = Group.Level1.class) @@ -95,13 +102,18 @@ public class AddCategoryForm implements AddCategoryDto { message = "{category-name-ru.invalid}", groups = Group.Level3.class ), + @Pattern( + regexp = CATEGORY_NAME_NO_REPEATING_HYPHENS_REGEXP, + message = "{value.repeating_hyphen}", + groups = Group.Level4.class + ), @Pattern( regexp = CATEGORY_NAME_NO_HYPHEN_REGEXP, message = "{value.hyphen}", - groups = Group.Level4.class + groups = Group.Level5.class ) }) - @UniqueCategoryName(lang = Lang.RU, groups = Group.Level5.class) + @UniqueCategoryName(lang = Lang.RU, groups = Group.Level6.class) private String nameRu; } diff --git a/src/main/java/ru/mystamps/web/model/Group.java b/src/main/java/ru/mystamps/web/model/Group.java index e7c8376431..fb8f92b750 100644 --- a/src/main/java/ru/mystamps/web/model/Group.java +++ b/src/main/java/ru/mystamps/web/model/Group.java @@ -33,5 +33,8 @@ interface Level4 { interface Level5 { } + + interface Level6 { + } } diff --git a/src/main/java/ru/mystamps/web/validation/ValidationRules.java b/src/main/java/ru/mystamps/web/validation/ValidationRules.java index e4135de02b..306639a272 100644 --- a/src/main/java/ru/mystamps/web/validation/ValidationRules.java +++ b/src/main/java/ru/mystamps/web/validation/ValidationRules.java @@ -42,6 +42,8 @@ public final class ValidationRules { public static final String CATEGORY_NAME_EN_REGEXP = "[- a-zA-Z]+"; public static final String CATEGORY_NAME_RU_REGEXP = "[- а-яёА-ЯЁ]+"; public static final String CATEGORY_NAME_NO_HYPHEN_REGEXP = "[ \\p{L}]([- \\p{L}]+[ \\p{L}])*"; + @SuppressWarnings({"PMD.LongVariable", "checkstyle:linelength"}) + public static final String CATEGORY_NAME_NO_REPEATING_HYPHENS_REGEXP = "(?!.+[-]{2,}).+"; public static final int COUNTRY_NAME_MIN_LENGTH = 3; public static final int COUNTRY_NAME_MAX_LENGTH = Db.Country.NAME_LENGTH; diff --git a/src/main/resources/ru/mystamps/i18n/ValidationMessages.properties b/src/main/resources/ru/mystamps/i18n/ValidationMessages.properties index 5c03208374..c56d33a980 100644 --- a/src/main/resources/ru/mystamps/i18n/ValidationMessages.properties +++ b/src/main/resources/ru/mystamps/i18n/ValidationMessages.properties @@ -24,6 +24,7 @@ value.too-short = Value is less than allowable minimum of {min} characters value.too-long = Value is greater than allowable maximum of {max} characters value.invalid-length = Value length must be equals to {max} characters value.hyphen = Value must not start or end with hyphen +value.repeating_hyphen = Value must not contain repetition of hyphen value.empty = Value must not be empty category-name-en.invalid = Category name must consist only latin letters, hyphen or spaces diff --git a/src/main/resources/ru/mystamps/i18n/ValidationMessages_ru.properties b/src/main/resources/ru/mystamps/i18n/ValidationMessages_ru.properties index d293a762b2..ce55e644c3 100644 --- a/src/main/resources/ru/mystamps/i18n/ValidationMessages_ru.properties +++ b/src/main/resources/ru/mystamps/i18n/ValidationMessages_ru.properties @@ -24,6 +24,7 @@ value.too-short = Значение должно быть не менее {min} value.too-long = Значение должно быть не более {max} символов value.invalid-length = Значение должно быть длинной {max} символов value.hyphen = Значение не должно начинаться или заканчиваться знаком дефиса +value.repeating_hyphen = Значение не должно содержать повторяющиеся знаки дефиса value.empty = Значение не должно быть пустым category-name-en.invalid = Название категории может содержать только латинские буквы, дефис или пробел diff --git a/src/test/java/ru/mystamps/web/tests/cases/WhenAdminAddCategory.java b/src/test/java/ru/mystamps/web/tests/cases/WhenAdminAddCategory.java index 8207a1dccc..d5086f62cd 100644 --- a/src/test/java/ru/mystamps/web/tests/cases/WhenAdminAddCategory.java +++ b/src/test/java/ru/mystamps/web/tests/cases/WhenAdminAddCategory.java @@ -184,6 +184,20 @@ public void categoryNameRuShouldNotEndsWithHyphen() { assertThat(page).field("nameRu").hasError(tr("value.hyphen")); } + + @Test(groups = "invalid", dependsOnGroups = "std") + public void categoryNameEnShouldNotContainRepeatedHyphens() { + page.addCategory("te--st", TEST_CATEGORY_NAME_RU); + + assertThat(page).field("name").hasError(tr("value.repeating_hyphen")); + } + + @Test(groups = "invalid", dependsOnGroups = "std") + public void categoryNameRuShouldNotContainRepeatedHyphens() { + page.addCategory(TEST_CATEGORY_NAME_EN, "те--ст"); + + assertThat(page).field("nameRu").hasError(tr("value.repeating_hyphen")); + } @Test(groups = "misc", dependsOnGroups = "std") public void categoryNameEnShouldBeStripedFromLeadingAndTrailingSpaces() { @@ -198,6 +212,20 @@ public void categoryNameRuShouldBeStripedFromLeadingAndTrailingSpaces() { assertThat(page).field("nameRu").hasValue("т3ст"); } + + @Test(groups = "misc", dependsOnGroups = "std") + public void categoryNameEnShouldReplaceRepeatedSpacesByOne() { + page.addCategory("t3 st", TEST_CATEGORY_NAME_RU); + + assertThat(page).field("name").hasValue("t3 st"); + } + + @Test(groups = "misc", dependsOnGroups = "std") + public void categoryNameRuShouldReplaceRepeatedSpacesByOne() { + page.addCategory(TEST_CATEGORY_NAME_EN, "т3 ст"); + + assertThat(page).field("nameRu").hasValue("т3 ст"); + } @Test(groups = "logic", dependsOnGroups = { "std", "invalid", "valid", "misc" }) public void shouldBeRedirectedToPageWithInfoAboutCategoryAfterCreation() {