From 2728a0ca01c615a194431f511b23c23f25f2de9b Mon Sep 17 00:00:00 2001 From: AlexGames73 Date: Fri, 11 Jan 2019 23:08:13 +0400 Subject: [PATCH] Add: register page, account info page --- .../UserSessionLoginFailureHandler.java | 9 +- .../ulstu/user/controller/UserController.java | 7 + .../user/controller/UserMVCController.java | 28 ++ .../user/service/UserSessionService.java | 10 +- src/main/resources/public/js/core.js | 7 +- .../public/js/react/accountPage/index.js | 55 ++++ .../js/react/loginPage/components/login.js | 51 ++- .../js/react/loginPage/components/register.js | 292 ++++++++++++++++-- .../public/js/react/loginPage/index.js | 11 +- src/main/resources/templates/acc-info.html | 12 +- src/main/resources/templates/activate.html | 8 +- src/main/resources/templates/default.html | 1 + 12 files changed, 410 insertions(+), 81 deletions(-) create mode 100644 src/main/java/ru/ulstu/user/controller/UserMVCController.java create mode 100644 src/main/resources/public/js/react/accountPage/index.js diff --git a/src/main/java/ru/ulstu/user/component/UserSessionLoginFailureHandler.java b/src/main/java/ru/ulstu/user/component/UserSessionLoginFailureHandler.java index 12e1670..5fd9d13 100644 --- a/src/main/java/ru/ulstu/user/component/UserSessionLoginFailureHandler.java +++ b/src/main/java/ru/ulstu/user/component/UserSessionLoginFailureHandler.java @@ -28,7 +28,14 @@ public class UserSessionLoginFailureHandler implements AuthenticationFailureHand throws IOException, ServletException { response.setStatus(HttpStatus.UNAUTHORIZED.value()); + HashMap data = new HashMap<>(); + data.put("data", null); + HashMap error = new HashMap<>(); + error.put("code", HttpStatus.UNAUTHORIZED.value()); + error.put("message", "Не удается войти.
Пожалуйста, проверьте правильность написания логина и пароля."); + data.put("error", error); + response.getOutputStream() - .write("Не удается войти.
Пожалуйста, проверьте правильность написания логина и пароля.".getBytes(StandardCharsets.UTF_8)); + .write(objectMapper.writeValueAsString(data).getBytes(StandardCharsets.UTF_8)); } } diff --git a/src/main/java/ru/ulstu/user/controller/UserController.java b/src/main/java/ru/ulstu/user/controller/UserController.java index d7db909..bdf9335 100644 --- a/src/main/java/ru/ulstu/user/controller/UserController.java +++ b/src/main/java/ru/ulstu/user/controller/UserController.java @@ -107,6 +107,13 @@ public class UserController extends OdinController { return new Response<>(userService.getUserWithRolesById(userId)); } + @GetMapping("/account") + @Secured({UserRoleConstants.ADMIN, UserRoleConstants.USER}) + public Response getUserBySession(@RequestParam("session_id") String sessionId){ + log.debug("REST: UserController.getUserBySession( {} )", sessionId); + return new Response<>(userSessionService.getUserDtoBySessionId(sessionId)); + } + @PostMapping("") @Secured(UserRoleConstants.ADMIN) diff --git a/src/main/java/ru/ulstu/user/controller/UserMVCController.java b/src/main/java/ru/ulstu/user/controller/UserMVCController.java new file mode 100644 index 0000000..5889fe1 --- /dev/null +++ b/src/main/java/ru/ulstu/user/controller/UserMVCController.java @@ -0,0 +1,28 @@ +package ru.ulstu.user.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import ru.ulstu.user.service.UserService; +import ru.ulstu.user.service.UserSessionService; + +@Controller +public class UserMVCController { + + private final Logger log = LoggerFactory.getLogger(UserMVCController.class); + + private final UserService userService; + private final UserSessionService userSessionService; + + public UserMVCController(UserService userService, UserSessionService userSessionService) { + this.userService = userService; + this.userSessionService = userSessionService; + } + + @GetMapping("/acc-info") + public String getAcc(){ + return "acc-info"; + } + +} diff --git a/src/main/java/ru/ulstu/user/service/UserSessionService.java b/src/main/java/ru/ulstu/user/service/UserSessionService.java index 0d985cd..b250065 100644 --- a/src/main/java/ru/ulstu/user/service/UserSessionService.java +++ b/src/main/java/ru/ulstu/user/service/UserSessionService.java @@ -10,6 +10,7 @@ import ru.ulstu.core.jpa.OffsetablePageRequest; import ru.ulstu.core.model.response.PageableItems; import ru.ulstu.user.error.UserNotFoundException; import ru.ulstu.user.model.User; +import ru.ulstu.user.model.UserDto; import ru.ulstu.user.model.UserSession; import ru.ulstu.user.model.UserSessionListDto; import ru.ulstu.user.repository.UserSessionRepository; @@ -22,10 +23,12 @@ public class UserSessionService { private final Logger log = LoggerFactory.getLogger(UserSessionService.class); private final UserSessionRepository userSessionRepository; private final UserService userService; + private final UserMapper userMapper; - public UserSessionService(UserSessionRepository userSessionRepository, UserService userService) { + public UserSessionService(UserSessionRepository userSessionRepository, UserService userService, UserMapper userMapper) { this.userSessionRepository = userSessionRepository; this.userService = userService; + this.userMapper = userMapper; } @Transactional(readOnly = true) @@ -54,4 +57,9 @@ public class UserSessionService { userSessionRepository.save(userSession); log.debug("User session {} closed", sessionId); } + + public UserDto getUserDtoBySessionId(String sessionId){ + final UserSession userSession = userSessionRepository.findOneBySessionId(sessionId); + return userMapper.userEntityToUserDto(userSession.getUser()); + } } diff --git a/src/main/resources/public/js/core.js b/src/main/resources/public/js/core.js index 5c9241c..2680262 100644 --- a/src/main/resources/public/js/core.js +++ b/src/main/resources/public/js/core.js @@ -56,7 +56,7 @@ function errorHandler(response, callBack, errorCallBack) { // TODO: add l10n // showFeedbackMessage(response.error.code + ": " + response.error.message, MessageTypesEnum.DANGER); if (!isEmpty(errorCallBack)) { - errorCallBack(response.data); + errorCallBack(response.error); } throw response.error.code + ": " + response.error.message + " / Details: " + response.error.data; @@ -121,7 +121,10 @@ function postToRest(url, postData, callBack, completeCallback, errorCallBack) { return; } completeCallback(); - } + }, + + }).fail(function (response) { + errorHandler(response.responseJSON, callBack, errorCallBack); }); } diff --git a/src/main/resources/public/js/react/accountPage/index.js b/src/main/resources/public/js/react/accountPage/index.js new file mode 100644 index 0000000..64a8d76 --- /dev/null +++ b/src/main/resources/public/js/react/accountPage/index.js @@ -0,0 +1,55 @@ +const { + LinearProgress, + CircularProgress, + Card, + CardHeader, + CardContent, + FormControl, + FormLabel, + TextField, + Button +} = window['material-ui']; +const { Component } = window['React']; +const React = window['React']; + +class Account extends Component{ + constructor(){ + super(); + + const session_id = document.cookie.toLowerCase().match(/jsessionid=(.*?).node0/)[1]; + $.getJSON("/api/1.0/users/account?session_id=" + session_id, + null, this.responseUserDto); + + this.state = { + userDto: null + }; + } + + responseUserDto = response => { + this.setState({ + userDto: response.data + }); + }; + + render(){ + return ( + this.state.userDto != null ? ( +
+ + + +

Login: {this.state.userDto.login}

+

Email: {this.state.userDto.email}

+
+
+
+ ) : ( +
+ +
+ ) + ) + } +} + +ReactDOM.render(, document.getElementById('react-account')); diff --git a/src/main/resources/public/js/react/loginPage/components/login.js b/src/main/resources/public/js/react/loginPage/components/login.js index db3f96f..7ceb875 100644 --- a/src/main/resources/public/js/react/loginPage/components/login.js +++ b/src/main/resources/public/js/react/loginPage/components/login.js @@ -7,51 +7,37 @@ const { TextField, Button } = window['material-ui']; +const React = window['React']; +const {Component} = React; -class LoginForm extends React.Component{ +class LoginForm extends Component{ state = { - isValidUsername: false, - isValidPassword: false, username: "", password: "", errorsMessage: "" }; - handleChangeUsername = event => { + handleChange = field => event => { this.setState({ - username: event.target.value, - isValidUsername: /^[_'.@A-Za-z0-9-]*$/.test(event.target.value) - }); - }; - - handleChangePassword = event => { - this.setState({ - password: event.target.value, - isValidPassword: (event.target.value.length > 4) + [field]: event.target.value, + ["isValid_"+field]: true }); }; handleSubmit = loginForm => () => { - if (loginForm.state.isValidUsername && loginForm.state.isValidPassword){ - $.post( - "/login", - loginForm.state, - this.handleResponseAjaxPost(loginForm)("success") - ).fail(this.handleResponseAjaxPost(loginForm)("error")); - } + $.post("/login", $('form.login-form').serialize(), + this.handleResponseAjaxPost(loginForm)("success")) + .fail(this.handleResponseAjaxPost(loginForm)("error")); }; handleResponseAjaxPost = loginForm => status => response => { if (status === "success"){ window.location.href = "/index"; - loginForm.setState({ - errorsMessage: "" - }); } else if (status === "error"){ + let responseJSON = JSON.parse(response.responseText); loginForm.setState({ - errorsMessage: response.responseText, + errorsMessage: responseJSON.error.message, password: "", - isValidPassword: false }) } }; @@ -61,7 +47,7 @@ class LoginForm extends React.Component{ (e.key === 'Enter' ? this.handleSubmit(this)() : null)} tabIndex="0"> -
+
diff --git a/src/main/resources/public/js/react/loginPage/components/register.js b/src/main/resources/public/js/react/loginPage/components/register.js index d2a66fc..ed70a7c 100644 --- a/src/main/resources/public/js/react/loginPage/components/register.js +++ b/src/main/resources/public/js/react/loginPage/components/register.js @@ -5,58 +5,290 @@ const { FormControl, FormLabel, TextField, - Button + Button, + InputAdornment, + IconButton, + Icon, + Dialog, + DialogTitle, + DialogContent, + DialogContentText, + DialogActions } = window['material-ui']; +const { Component } = window['React']; +const React = window['React']; + +class RegisterForm extends Component{ + validate(field, state) { + switch (field) { + case "login": + return ( + (state[field].length >= 4) && + /^[_'.@A-Za-z0-9-]*$/.test(state[field]) + ); + case "password": + return ( + (state[field].length >= 6) + ); + case "passwordConfirm": + return ( + (state[field].length >= 6) && + (state[field] === state["password"]) + ); + case "email": + return ( + (/.+@.+\..+/i.test(state[field])) + ); + case "firstName": + return ( + (state[field].length >= 2) + ); + case "lastName": + return ( + (state[field].length >= 2) + ); + } + } + fields = ["login", "password", "passwordConfirm", "email", "firstName", "lastName"]; + labels = { + login: "Логин", + password: "Пароль", + passwordConfirm: "Подтверждение пароля", + email: "Email", + firstName: "Имя", + lastName: "Фамилия", + }; + typeInputs = { + login: "text", + password: "password", + passwordConfirm: "password", + email: "email", + firstName: "text", + lastName: "text", + }; + + dialogContents = { + login: ( + + Длина логина должна быть не менее 4 символов и не превышать 50 символов.
+ Логин может состоять из:
+     1. Строчных или заглавных букв латинского алфавита
+     2. Цифр
+     3. знаков препинания _'.@-
+
+ ), + password: ( + + Длина пароля должна быть не менее 6 символов и не превышать 50 символов. + + ), + passwordConfirm: ( + + Пароли должны совпадать и соответствовать требованиям пароля + + ), + email: ( + + Почта должна соответвовать примеру: example@domain.com + + ), + firstName: ( + + Длина имени должна быть не менее 2 символов и не превышать 50 символов. + + ), + lastName: ( + + Длина Фамилии должна быть не менее 2 символов и не превышать 50 символов. + + ), + }; -class RegisterForm extends React.Component{ state = { - isValidUsername: false, - isValidPassword: false, - username: "", + isValid_login: true, + isValid_password: true, + isValid_passwordConfirm: true, + isValid_email: true, + isValid_firstName: true, + isValid_lastName: true, + login: "", password: "", - errorsMessage: "" + passwordConfirm: "", + email: "", + firstName: "", + lastName: "", + error_login: "", + error_password: "", + error_passwordConfirm: "", + error_email: "", + error_firstName: "", + error_lastName: "", + isComplete: false, + errorsMessage: "", + infoAbout: "", + infoIsOpen: false, }; - handleChangeUsername = event => { + handleChange = field => event => { this.setState({ - username: event.target.value, - isValidUsername: (event.target.value.length > 4) + [field]: event.target.value, + ["isValid_"+field]: true }); }; - handleChangePassword = event => { - this.setState({ - password: event.target.value, - isValidPassword: (event.target.value.length > 4) + isValid = state => { + let result = true; + this.fields.forEach(field => { + result = result && state["isValid_"+field]; + }); + return result; + }; + + registerFormToJson = function () { + let formData = {}; + $(".register-form").find(":input").not(":button").each(function () { + if ($(this).val() == null || $(this).val() === "") { + return true; + } + formData[$(this).attr("name")] = $(this).val(); }); + return JSON.stringify(formData); }; - handleSubmit = loginForm => () => { - if (loginForm.state.isValidUsername && loginForm.state.isValidPassword){ - $.post( - "/api/1.0/users/register", - loginForm.state, - this.handleResponseAjaxPost(loginForm)("success") - ).fail(this.handleResponseAjaxPost(loginForm)("error")); + handleSubmit = registerForm => () => { + let valids = {}; + this.fields.forEach(field => { + valids["isValid_"+field]=this.validate(field, registerForm.state) + }); + this.setState(valids); + if (this.isValid(valids)){ + postToRest("/api/1.0/users/register", this.registerFormToJson(), null, + this.handleResponseAjaxPost(registerForm)("success"), + this.handleResponseAjaxPost(registerForm)("error")); } }; - handleResponseAjaxPost = loginForm => status => response => { + handleResponseAjaxPost = registerForm => status => response => { if (status === "success"){ - window.location.href = "/index"; - loginForm.setState({ - errorsMessage: "" + registerForm.setState({ + isComplete: true }); } else if (status === "error"){ - loginForm.setState({ - errorsMessage: response.responseText, - password: "", - isValidPassword: false - }) + switch (response.code) { + case 103: + registerForm.setState({ + errorsMessage: response.message, + error_login: "Пользователь с таким логином уже существует", + isValid_login: false + }); + break; + case 102: + registerForm.setState({ + errorsMessage: response.message, + error_email: "Пользователь с таким адресом уже существует", + isValid_email: false + }); + break; + default: + registerForm.setState({ + errorsMessage: response.message + }); + break; + } } }; + handleClickInfo = field => () => { + this.setState({ + infoAbout: field, + infoIsOpen: true, + }); + }; + + handleCloseInfo = () => { + this.setState({ + infoIsOpen: false + }) + }; + + getForm = () => { + return ( +
+ + +
+
+
+ {this.fields.map(field => ( + + + info + + + ), + name: field + }} + type={this.typeInputs[field]} + /> + ))} + + {this.labels[this.state.infoAbout]} + + {this.dialogContents[this.state.infoAbout]} + + + + + + +
+
+ ); + }; + + getCompleteContent = () => { + return ( +
+
Вам на почту {this.state.email} придет письмо с активацией аккаунта в течении нескольких минут.
+
+ ); + }; + render(){ - return
; + return ( + (e.key === 'Enter' ? this.handleSubmit(this)() : null)} tabIndex="0"> + + + {this.state.isComplete ? + this.getCompleteContent() : + this.getForm()} + + + ); } } \ No newline at end of file diff --git a/src/main/resources/public/js/react/loginPage/index.js b/src/main/resources/public/js/react/loginPage/index.js index 05929fe..4b39c6a 100644 --- a/src/main/resources/public/js/react/loginPage/index.js +++ b/src/main/resources/public/js/react/loginPage/index.js @@ -1,6 +1,9 @@ -let {Button, Icon} = window['material-ui']; +const {Button, Icon} = window['material-ui']; +const {render} = window['ReactDOM']; +const React = window['React']; +const {Component} = React; -class LoginPage extends React.Component{ +class LoginPage extends Component{ state = { isLogin: true, isRegister: false @@ -18,7 +21,7 @@ class LoginPage extends React.Component{ isLogin: false, isRegister: true }); - } + }; render() { this.form = null; @@ -46,4 +49,4 @@ class LoginPage extends React.Component{ } } -ReactDOM.render(, document.getElementById("loginForm")); +render(, document.getElementById("loginForm")); diff --git a/src/main/resources/templates/acc-info.html b/src/main/resources/templates/acc-info.html index 0720627..6933fa8 100644 --- a/src/main/resources/templates/acc-info.html +++ b/src/main/resources/templates/acc-info.html @@ -5,10 +5,14 @@ xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4" layout:decorator="default"> -
- Login:

- Имя:

- Фамилия:

+
+
+ +
+
+ +
+
\ No newline at end of file diff --git a/src/main/resources/templates/activate.html b/src/main/resources/templates/activate.html index b20a284..c62a822 100644 --- a/src/main/resources/templates/activate.html +++ b/src/main/resources/templates/activate.html @@ -12,11 +12,6 @@ class="fa fa-plane fa-4" aria-hidden="true"> Balance
- +