diff --git a/resources/WEB-INF/jsp/registration.jsp b/resources/WEB-INF/jsp/registration.jsp index 3d7546e..e78000b 100644 --- a/resources/WEB-INF/jsp/registration.jsp +++ b/resources/WEB-INF/jsp/registration.jsp @@ -1,4 +1,6 @@ <%@ page contentType="text/html;charset=UTF-8" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> + Charm Registration @@ -20,6 +22,13 @@ + +
+ + ${wordBundle.getWord(error)} +
+
+
<%@ include file="footer.jsp" %> diff --git a/resources/words.properties b/resources/words.properties index ac8383d..f487cad 100644 --- a/resources/words.properties +++ b/resources/words.properties @@ -7,6 +7,10 @@ confirm-password=Confirm password delete=Delete email=Email email-warning=Changing your mail may have negative effects +error.age.invalid=Age must be between 18 and 100 years old +error.email.exist=This email already exists +error.email.invalid=Invalid email +error.password.invalid=Invalid password female=Female gender=Gender inactive=Inactive @@ -16,6 +20,9 @@ other=Other page-bad-request=Bad request page-not-found=Page not found password=Password +photo=Photo save=Save status=Status -surname=Surname \ No newline at end of file +surname=Surname +unexpected-error=Unexpected error +update=Update \ No newline at end of file diff --git a/resources/words_en.properties b/resources/words_en.properties index ac8383d..f487cad 100644 --- a/resources/words_en.properties +++ b/resources/words_en.properties @@ -7,6 +7,10 @@ confirm-password=Confirm password delete=Delete email=Email email-warning=Changing your mail may have negative effects +error.age.invalid=Age must be between 18 and 100 years old +error.email.exist=This email already exists +error.email.invalid=Invalid email +error.password.invalid=Invalid password female=Female gender=Gender inactive=Inactive @@ -16,6 +20,9 @@ other=Other page-bad-request=Bad request page-not-found=Page not found password=Password +photo=Photo save=Save status=Status -surname=Surname \ No newline at end of file +surname=Surname +unexpected-error=Unexpected error +update=Update \ No newline at end of file diff --git a/resources/words_ru.properties b/resources/words_ru.properties index 1cf55c7..879135e 100644 --- a/resources/words_ru.properties +++ b/resources/words_ru.properties @@ -7,6 +7,10 @@ confirm-password=\u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u0 delete=\u0423\u0434\u0430\u043B\u0438\u0442\u044C email=\u041F\u043E\u0447\u0442\u0430 email-warning=\u0421\u043C\u0435\u043D\u0430 \u043F\u043E\u0447\u0442\u044B \u043C\u043E\u0436\u0435\u0442 \u043F\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043A \u043D\u0435\u0436\u0435\u043B\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u043F\u043E\u0441\u043B\u0435\u0434\u0441\u0442\u0432\u0438\u044F\u043C +error.age.invalid=\u0412\u043E\u0437\u0440\u0430\u0441\u0442 \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043E\u0442 18 \u0434\u043E 100 \u043B\u0435\u0442 +error.email.exist=\u0422\u0430\u043A\u0430\u044F \u043F\u043E\u0447\u0442\u0430 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 +error.email.invalid=\u041D\u0435\u0432\u0435\u0440\u043D\u0430\u044F \u043F\u043E\u0447\u0442\u0430 +error.password.invalid=\u041D\u0435\u043F\u043E\u0434\u0445\u043E\u0434\u044F\u0449\u0438\u0439 \u043F\u0430\u0440\u043E\u043B\u044C female=\u0416\u0435\u043D\u0449\u0438\u043D\u0430 gender=\u041F\u043E\u043B inactive=\u041D\u0435\u0430\u043A\u0442\u0438\u0432\u043D\u044B\u0439 @@ -16,6 +20,9 @@ other=\u0414\u0440\u0443\u0433\u043E\u0435 page-bad-request=\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u0437\u0430\u043F\u0440\u043E\u0441 page-not-found=\u0421\u0442\u0440\u0430\u043D\u0438\u0446\u0430 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u0430 password=\u041F\u0430\u0440\u043E\u043B\u044C +photo=\u0424\u043E\u0442\u043E save=\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C status=\u0421\u0442\u0430\u0442\u0443\u0441 -surname=\u0424\u0430\u043C\u0438\u043B\u0438\u044F \ No newline at end of file +surname=\u0424\u0430\u043C\u0438\u043B\u0438\u044F +unexpected-error=\u041D\u0435\u043F\u0440\u0435\u0434\u0432\u0438\u0434\u0435\u043D\u043D\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 +update=\u041E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \ No newline at end of file diff --git a/src/ru/charm/back/controller/LikeController.java b/src/ru/charm/back/controller/LikeController.java deleted file mode 100644 index 715cb42..0000000 --- a/src/ru/charm/back/controller/LikeController.java +++ /dev/null @@ -1,33 +0,0 @@ -package ru.charm.back.controller; - -import jakarta.servlet.ServletConfig; -import jakarta.servlet.ServletException; -import jakarta.servlet.annotation.WebServlet; -import jakarta.servlet.http.HttpServlet; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import java.io.IOException; - -@WebServlet("/like") -public class LikeController extends HttpServlet { - @Override - public void init(ServletConfig config) throws ServletException { - System.out.println("LikeController init" + config.getServletName() ); - super.init(config); - } - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - resp.setContentType("text/plain"); - System.out.println("User-Agent: " + req.getHeader("User-Agent")); - resp.getWriter().write("Like count: 101"); - resp.setHeader("X-Custom-Header", "Zalupa"); - } - - @Override - public void destroy() { - System.out.println("LikeController destroy"); - super.destroy(); - } -} diff --git a/src/ru/charm/back/controller/RegistrationController.java b/src/ru/charm/back/controller/RegistrationController.java index 2f413a6..b60e0ce 100644 --- a/src/ru/charm/back/controller/RegistrationController.java +++ b/src/ru/charm/back/controller/RegistrationController.java @@ -9,6 +9,8 @@ import lombok.extern.slf4j.Slf4j; import ru.charm.back.dto.RegistrationDto; import ru.charm.back.mapper.RequestToRegistrationDtoMapper; import ru.charm.back.service.ProfileService; +import ru.charm.back.validator.RegistrationValidator; +import ru.charm.back.validator.ValidationResult; import java.io.IOException; @@ -18,6 +20,7 @@ public class RegistrationController extends HttpServlet { private final ProfileService service = ProfileService.getInstance(); private final RequestToRegistrationDtoMapper requestToRegistrationDtoMapper = RequestToRegistrationDtoMapper.getInstance(); + private final RegistrationValidator validator = RegistrationValidator.getInstance(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { @@ -25,8 +28,16 @@ public class RegistrationController extends HttpServlet { } @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { RegistrationDto dto = requestToRegistrationDtoMapper.map(req); + + ValidationResult validationResult = validator.validate(dto); + if (!validationResult.isValid()) { + req.setAttribute("errors", validationResult.getErrors()); + doGet(req, resp); + return; + } + Long id = service.save(dto); log.info("Profile with the email address {} has been registered with id {}", dto.getEmail(), id); resp.sendRedirect(String.format("/profile?id=%s", id)); diff --git a/src/ru/charm/back/controller/filter/HiddenHttpMethodFilter.java b/src/ru/charm/back/controller/filter/HiddenHttpMethodFilter.java index d45302f..54537d1 100644 --- a/src/ru/charm/back/controller/filter/HiddenHttpMethodFilter.java +++ b/src/ru/charm/back/controller/filter/HiddenHttpMethodFilter.java @@ -5,6 +5,8 @@ import jakarta.servlet.annotation.WebFilter; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequestWrapper; import jakarta.servlet.http.HttpServletResponse; +import lombok.Getter; +import lombok.Setter; import ru.charm.back.model.Gender; import java.io.IOException; @@ -39,16 +41,13 @@ public class HiddenHttpMethodFilter implements Filter { public static class HttpMethodRequestWrapper extends HttpServletRequestWrapper { + @Setter + @Getter public final String method; public HttpMethodRequestWrapper(HttpServletRequest request, String method) { super(request); this.method = method; } - - @Override - public String getMethod() { - return method; - } } } diff --git a/src/ru/charm/back/service/ProfileService.java b/src/ru/charm/back/service/ProfileService.java index 3d95643..05fb635 100644 --- a/src/ru/charm/back/service/ProfileService.java +++ b/src/ru/charm/back/service/ProfileService.java @@ -48,21 +48,11 @@ public class ProfileService { public void update(ProfileUpdateDto dto) { dao.findById(dto.getId()) .ifPresent(profile -> { - checkEmail(profile.getEmail(), dto.getEmail()); dao.update(profileUpdateDtoToProfileMapper.map(dto, profile)); } ); } - private void checkEmail(String oldEmail, String newEmail) { - if (newEmail == null) return; - Set emails = dao.getAllEmails(); - if (!Objects.equals(oldEmail, newEmail) && - emails.contains(newEmail)) { - throw new DuplicateEmailException(); - } - } - public boolean delete(Long id) { return dao.delete(id); } diff --git a/src/ru/charm/back/utils/StringUtils.java b/src/ru/charm/back/utils/StringUtils.java index 6b9da5e..a6652d5 100644 --- a/src/ru/charm/back/utils/StringUtils.java +++ b/src/ru/charm/back/utils/StringUtils.java @@ -2,8 +2,13 @@ package ru.charm.back.utils; import lombok.experimental.UtilityClass; +import java.util.regex.Pattern; + @UtilityClass public class StringUtils { + public static final Pattern VALID_EMAIL_ADDRESS_REGEX = + Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$", Pattern.CASE_INSENSITIVE); + public static boolean isBlank(String str) { return str == null || str.isBlank(); } diff --git a/src/ru/charm/back/validator/RegistrationValidator.java b/src/ru/charm/back/validator/RegistrationValidator.java new file mode 100644 index 0000000..e1621e3 --- /dev/null +++ b/src/ru/charm/back/validator/RegistrationValidator.java @@ -0,0 +1,35 @@ +package ru.charm.back.validator; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import ru.charm.back.dao.ProfileDao; +import ru.charm.back.dto.RegistrationDto; +import ru.charm.back.mapper.ProfileUpdateDtoToProfileMapper; + +import static ru.charm.back.utils.StringUtils.VALID_EMAIL_ADDRESS_REGEX; +import static ru.charm.back.utils.StringUtils.isBlank; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class RegistrationValidator implements Validator { + private static final RegistrationValidator INSTANCE = new RegistrationValidator(); + public static RegistrationValidator getInstance() { return INSTANCE; } + + private final ProfileDao dao = ProfileDao.getInstance(); + + @Override + public ValidationResult validate(RegistrationDto dto) { + ValidationResult validationResult = new ValidationResult(); + + if (isBlank(dto.getEmail()) || !VALID_EMAIL_ADDRESS_REGEX.matcher(dto.getEmail()).matches()) { + validationResult.addError("error.email.invalid"); + } else if (dao.getAllEmails().contains(dto.getEmail())) { + validationResult.addError("error.email.exists"); + } + + if (isBlank(dto.getPassword())) { + validationResult.addError("error.password.invalid"); + } + + return validationResult; + } +} diff --git a/src/ru/charm/back/validator/ValidationResult.java b/src/ru/charm/back/validator/ValidationResult.java new file mode 100644 index 0000000..6d3ef45 --- /dev/null +++ b/src/ru/charm/back/validator/ValidationResult.java @@ -0,0 +1,20 @@ +package ru.charm.back.validator; + +import java.util.ArrayList; +import java.util.List; + +public class ValidationResult { + private final List errors = new ArrayList<>(); + + public boolean isValid() { + return errors.isEmpty(); + } + + public void addError(String code) { + errors.add(code); + } + + public List getErrors() { + return new ArrayList<>(errors); + } +} diff --git a/src/ru/charm/back/validator/Validator.java b/src/ru/charm/back/validator/Validator.java new file mode 100644 index 0000000..dcc785a --- /dev/null +++ b/src/ru/charm/back/validator/Validator.java @@ -0,0 +1,5 @@ +package ru.charm.back.validator; + +public interface Validator { + ValidationResult validate(T object); +}