Add ReactJS to project
This commit is contained in:
parent
c17591bf10
commit
383bbc343f
@ -120,6 +120,10 @@ dependencies {
|
|||||||
compile group: 'org.webjars', name: 'jquery', version: '3.3.1-1'
|
compile group: 'org.webjars', name: 'jquery', version: '3.3.1-1'
|
||||||
compile group: 'org.webjars.npm', name: 'jquery.easing', version: '1.4.1'
|
compile group: 'org.webjars.npm', name: 'jquery.easing', version: '1.4.1'
|
||||||
compile group: 'org.webjars', name: 'font-awesome', version: '4.7.0'
|
compile group: 'org.webjars', name: 'font-awesome', version: '4.7.0'
|
||||||
|
compile group: 'org.webjars.npm', name: 'react', version: '16.7.0'
|
||||||
|
compile group: 'org.webjars.npm', name: 'react-dom', version: '16.7.0'
|
||||||
|
compile group: 'org.webjars.npm', name: 'material-ui__core', version: '3.5.1'
|
||||||
|
compile group: 'org.webjars.npm', name: 'babel-standalone', version: '6.26.0'
|
||||||
|
|
||||||
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.5.0'
|
compile group: 'io.springfox', name: 'springfox-swagger2', version: '2.5.0'
|
||||||
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.5.0'
|
compile group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.5.0'
|
||||||
|
@ -10,7 +10,7 @@ public class Constants {
|
|||||||
public static final String LOGIN_REGEX = "^[_'.@A-Za-z0-9-]*$";
|
public static final String LOGIN_REGEX = "^[_'.@A-Za-z0-9-]*$";
|
||||||
|
|
||||||
public static final String COOKIES_NAME = "JSESSIONID";
|
public static final String COOKIES_NAME = "JSESSIONID";
|
||||||
public static final String LOGOUT_URL = "/login?logout";
|
public static final String LOGOUT_URL = "/login";
|
||||||
public static final String SESSION_ID_ATTR = "sessionId";
|
public static final String SESSION_ID_ATTR = "sessionId";
|
||||||
public static final int SESSION_TIMEOUT_SECONDS = 30 * 60;
|
public static final int SESSION_TIMEOUT_SECONDS = 30 * 60;
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
|||||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||||
import ru.ulstu.user.controller.UserController;
|
import ru.ulstu.user.controller.UserController;
|
||||||
@ -33,17 +34,20 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
private final BCryptPasswordEncoder bCryptPasswordEncoder;
|
private final BCryptPasswordEncoder bCryptPasswordEncoder;
|
||||||
private final AuthenticationSuccessHandler authenticationSuccessHandler;
|
private final AuthenticationSuccessHandler authenticationSuccessHandler;
|
||||||
|
private final AuthenticationFailureHandler authenticationFailureHandler;
|
||||||
private final LogoutSuccessHandler logoutSuccessHandler;
|
private final LogoutSuccessHandler logoutSuccessHandler;
|
||||||
private final ApplicationProperties applicationProperties;
|
private final ApplicationProperties applicationProperties;
|
||||||
|
|
||||||
public SecurityConfiguration(UserService userService,
|
public SecurityConfiguration(UserService userService,
|
||||||
BCryptPasswordEncoder bCryptPasswordEncoder,
|
BCryptPasswordEncoder bCryptPasswordEncoder,
|
||||||
AuthenticationSuccessHandler authenticationSuccessHandler,
|
AuthenticationSuccessHandler authenticationSuccessHandler,
|
||||||
|
AuthenticationFailureHandler authenticationFailureHandler,
|
||||||
LogoutSuccessHandler logoutSuccessHandler,
|
LogoutSuccessHandler logoutSuccessHandler,
|
||||||
ApplicationProperties applicationProperties) {
|
ApplicationProperties applicationProperties) {
|
||||||
this.userService = userService;
|
this.userService = userService;
|
||||||
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
|
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
|
||||||
this.authenticationSuccessHandler = authenticationSuccessHandler;
|
this.authenticationSuccessHandler = authenticationSuccessHandler;
|
||||||
|
this.authenticationFailureHandler = authenticationFailureHandler;
|
||||||
this.logoutSuccessHandler = logoutSuccessHandler;
|
this.logoutSuccessHandler = logoutSuccessHandler;
|
||||||
this.applicationProperties = applicationProperties;
|
this.applicationProperties = applicationProperties;
|
||||||
}
|
}
|
||||||
@ -75,6 +79,7 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|||||||
.and()
|
.and()
|
||||||
.formLogin()
|
.formLogin()
|
||||||
.loginPage("/login")
|
.loginPage("/login")
|
||||||
|
.failureHandler(authenticationFailureHandler)
|
||||||
.successHandler(authenticationSuccessHandler)
|
.successHandler(authenticationSuccessHandler)
|
||||||
.permitAll()
|
.permitAll()
|
||||||
.and()
|
.and()
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
package ru.ulstu.user.component;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class UserSessionLoginFailureHandler implements AuthenticationFailureHandler {
|
||||||
|
|
||||||
|
private ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAuthenticationFailure(
|
||||||
|
HttpServletRequest request,
|
||||||
|
HttpServletResponse response,
|
||||||
|
AuthenticationException exception)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
|
||||||
|
response.setStatus(HttpStatus.UNAUTHORIZED.value());
|
||||||
|
response.getOutputStream()
|
||||||
|
.write("<b>Не удается войти.</b><br>Пожалуйста, проверьте правильность написания <b>логина</b> и <b>пароля</b>.".getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
}
|
@ -34,5 +34,5 @@ liquibase.change-log=classpath:db/changelog-master.xml
|
|||||||
# Application Settings
|
# Application Settings
|
||||||
ng-tracker.base-url=http://127.0.0.1:8080
|
ng-tracker.base-url=http://127.0.0.1:8080
|
||||||
ng-tracker.undead-user-login=admin
|
ng-tracker.undead-user-login=admin
|
||||||
ng-tracker.dev-mode=true
|
ng-tracker.dev-mode=false
|
||||||
ng-tracker.use-https=false
|
ng-tracker.use-https=false
|
100
src/main/resources/public/js/react/loginPage/components/login.js
Normal file
100
src/main/resources/public/js/react/loginPage/components/login.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
const {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardContent,
|
||||||
|
FormControl,
|
||||||
|
FormLabel,
|
||||||
|
TextField,
|
||||||
|
Button
|
||||||
|
} = window['material-ui'];
|
||||||
|
|
||||||
|
class LoginForm extends React.Component{
|
||||||
|
state = {
|
||||||
|
isValidUsername: false,
|
||||||
|
isValidPassword: false,
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
errorsMessage: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChangeUsername = 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)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSubmit = loginForm => () => {
|
||||||
|
if (loginForm.state.isValidUsername && loginForm.state.isValidPassword){
|
||||||
|
$.post(
|
||||||
|
"/login",
|
||||||
|
loginForm.state,
|
||||||
|
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"){
|
||||||
|
loginForm.setState({
|
||||||
|
errorsMessage: response.responseText,
|
||||||
|
password: "",
|
||||||
|
isValidPassword: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render(){
|
||||||
|
return (
|
||||||
|
<Card onKeyPress={e => (e.key === 'Enter' ? this.handleSubmit(this)() : null)} tabIndex="0">
|
||||||
|
<CardHeader title="Вход"/>
|
||||||
|
<CardContent>
|
||||||
|
<form>
|
||||||
|
<FormControl component="fieldset" style={{width: '100%'}}>
|
||||||
|
<FormLabel error={true}>
|
||||||
|
<div
|
||||||
|
className="Container"
|
||||||
|
dangerouslySetInnerHTML={{__html: this.state.errorsMessage}}>
|
||||||
|
</div>
|
||||||
|
</FormLabel>
|
||||||
|
<TextField
|
||||||
|
label="Логин"
|
||||||
|
value={this.state.username}
|
||||||
|
onChange={this.handleChangeUsername}
|
||||||
|
margin="normal"
|
||||||
|
error={!this.state.isValidUsername}
|
||||||
|
helperText={!this.state.isValidUsername ? "Логин не соответствует требованиям ^[_'.@A-Za-z0-9-]*$" : ""}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label="Пароль"
|
||||||
|
value={this.state.password}
|
||||||
|
onChange={this.handleChangePassword}
|
||||||
|
margin="normal"
|
||||||
|
error={!this.state.isValidPassword}
|
||||||
|
helperText={!this.state.isValidPassword ? "Пароль должен содержать 5 символов" : ""}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={this.handleSubmit(this)}
|
||||||
|
style={{margin: 'auto'}}
|
||||||
|
disabled={!this.state.isValidUsername || !this.state.isValidPassword}
|
||||||
|
>Войти</Button>
|
||||||
|
</FormControl>
|
||||||
|
</form>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,62 @@
|
|||||||
|
const {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardContent,
|
||||||
|
FormControl,
|
||||||
|
FormLabel,
|
||||||
|
TextField,
|
||||||
|
Button
|
||||||
|
} = window['material-ui'];
|
||||||
|
|
||||||
|
class RegisterForm extends React.Component{
|
||||||
|
state = {
|
||||||
|
isValidUsername: false,
|
||||||
|
isValidPassword: false,
|
||||||
|
username: "",
|
||||||
|
password: "",
|
||||||
|
errorsMessage: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChangeUsername = event => {
|
||||||
|
this.setState({
|
||||||
|
username: event.target.value,
|
||||||
|
isValidUsername: (event.target.value.length > 4)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChangePassword = event => {
|
||||||
|
this.setState({
|
||||||
|
password: event.target.value,
|
||||||
|
isValidPassword: (event.target.value.length > 4)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleResponseAjaxPost = loginForm => status => response => {
|
||||||
|
if (status === "success"){
|
||||||
|
window.location.href = "/index";
|
||||||
|
loginForm.setState({
|
||||||
|
errorsMessage: ""
|
||||||
|
});
|
||||||
|
} else if (status === "error"){
|
||||||
|
loginForm.setState({
|
||||||
|
errorsMessage: response.responseText,
|
||||||
|
password: "",
|
||||||
|
isValidPassword: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
render(){
|
||||||
|
return <div> </div>;
|
||||||
|
}
|
||||||
|
}
|
49
src/main/resources/public/js/react/loginPage/index.js
Normal file
49
src/main/resources/public/js/react/loginPage/index.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
let {Button, Icon} = window['material-ui'];
|
||||||
|
|
||||||
|
class LoginPage extends React.Component{
|
||||||
|
state = {
|
||||||
|
isLogin: true,
|
||||||
|
isRegister: false
|
||||||
|
};
|
||||||
|
|
||||||
|
handleOpenLogin = loginPage => () => {
|
||||||
|
loginPage.setState({
|
||||||
|
isLogin: true,
|
||||||
|
isRegister: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleOpenRegister = loginPage => () => {
|
||||||
|
loginPage.setState({
|
||||||
|
isLogin: false,
|
||||||
|
isRegister: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
this.form = null;
|
||||||
|
if (this.state.isLogin)
|
||||||
|
this.form = <LoginForm/>;
|
||||||
|
else if (this.state.isRegister)
|
||||||
|
this.form = <RegisterForm/>;
|
||||||
|
if ($('.isAuth').length === 0)
|
||||||
|
return (
|
||||||
|
<div className="login-page" style={{width: '50%', margin: 'auto'}}>
|
||||||
|
<div className="text-center" style={{marginBottom: '10px'}}>
|
||||||
|
<Button variant="contained" onClick={this.handleOpenLogin(this)} style={{marginRight: '10px'}}>Авторизация</Button>
|
||||||
|
<Button variant="contained" onClick={this.handleOpenRegister(this)}>Регистрация</Button>
|
||||||
|
</div>
|
||||||
|
{this.form}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
else
|
||||||
|
return (
|
||||||
|
<div className="col-lg-12 text-center">
|
||||||
|
<h2 className="section-heading text-uppercase">Ты уже авторизован</h2>
|
||||||
|
<Button variant="extendedFab" href="/"><Icon>navigation</Icon>Вернуться на главную</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactDOM.render(<LoginPage/>, document.getElementById("loginForm"));
|
118
src/main/resources/public/js/react/mainPage/navbar.js
Normal file
118
src/main/resources/public/js/react/mainPage/navbar.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
const {
|
||||||
|
Drawer, AppBar, Toolbar,
|
||||||
|
IconButton, Icon,
|
||||||
|
Typography, Menu, MenuItem,
|
||||||
|
List, ListItem, ListItemIcon,
|
||||||
|
ListItemText, Divider, ListSubheader,
|
||||||
|
withStyles
|
||||||
|
} = window['material-ui'];
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
root: {
|
||||||
|
flexGrow: 1,
|
||||||
|
},
|
||||||
|
grow: {
|
||||||
|
flexGrow: 1,
|
||||||
|
},
|
||||||
|
menuButton: {
|
||||||
|
marginLeft: -12,
|
||||||
|
marginRight: 20,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
class Navbar extends React.Component {
|
||||||
|
state = {
|
||||||
|
anchorEl: null,
|
||||||
|
left: false
|
||||||
|
};
|
||||||
|
|
||||||
|
handleMenu = event => {
|
||||||
|
this.setState({ anchorEl: event.currentTarget });
|
||||||
|
};
|
||||||
|
|
||||||
|
handleDrawer = value => () => {
|
||||||
|
this.setState({
|
||||||
|
left: value
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleClose = () => {
|
||||||
|
this.setState({ anchorEl: null });
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { classes } = this.props;
|
||||||
|
const { anchorEl } = this.state;
|
||||||
|
const open = Boolean(anchorEl);
|
||||||
|
|
||||||
|
let accountContent = null;
|
||||||
|
if ($('.isAuth').length !== 0)
|
||||||
|
accountContent = (
|
||||||
|
<div className="account-menu">
|
||||||
|
<IconButton
|
||||||
|
aria-owns={open ? 'menu-appbar' : undefined}
|
||||||
|
aria-haspopup="true"
|
||||||
|
onClick={this.handleMenu}
|
||||||
|
color="inherit"
|
||||||
|
>
|
||||||
|
{$('.isAuth')[0].textContent} <Icon>account_circle</Icon>
|
||||||
|
</IconButton>
|
||||||
|
<Menu
|
||||||
|
id="menu-appbar"
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'right',
|
||||||
|
}}
|
||||||
|
transformOrigin={{
|
||||||
|
vertical: 'top',
|
||||||
|
horizontal: 'right',
|
||||||
|
}}
|
||||||
|
open={open}
|
||||||
|
onClose={this.handleClose}
|
||||||
|
>
|
||||||
|
<MenuItem onClick={()=>{window.location.href="/acc-info"}}>Мой аккаунт</MenuItem>
|
||||||
|
<MenuItem onClick={()=>{window.location.href="/logout"}}>Выход</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.root}>
|
||||||
|
<AppBar>
|
||||||
|
<Toolbar>
|
||||||
|
<IconButton className={classes.menuButton} onClick={this.handleDrawer(true)} color="inherit" aria-label="Menu">
|
||||||
|
<Icon>menu</Icon>
|
||||||
|
</IconButton>
|
||||||
|
<Drawer open={this.state.left} onClose={this.handleDrawer(false)}>
|
||||||
|
<div className={classes.list} style={{width: '16rem'}}>
|
||||||
|
<List subheader={<ListSubheader component="div">Ссылки</ListSubheader>}>
|
||||||
|
{[
|
||||||
|
{label: 'НИО-17', link: '#landing'},
|
||||||
|
{label: 'Сайт кафедры', link: 'http://is.ulstu.ru'},
|
||||||
|
{label: 'КИАС РФФИ', link: 'https://kias.rfbr.ru/'}
|
||||||
|
].map(item => (
|
||||||
|
<ListItem button key={item.label} onClick={() => {window.location.href=item.link}}>
|
||||||
|
<ListItemIcon><Icon>label_important</Icon></ListItemIcon>
|
||||||
|
<ListItemText primary={item.label} />
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
|
<Typography variant="h6" color="inherit" className={classes.grow}>
|
||||||
|
NG-Tracker
|
||||||
|
</Typography>
|
||||||
|
{accountContent}
|
||||||
|
</Toolbar>
|
||||||
|
</AppBar>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Navbar.propTypes = {
|
||||||
|
classes: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
ReactDOM.render(React.createElement(withStyles(styles)(Navbar), null, null), document.getElementById('react-navbar'));
|
14
src/main/resources/templates/acc-info.html
Normal file
14
src/main/resources/templates/acc-info.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
xmlns:form="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
|
||||||
|
layout:decorator="default">
|
||||||
|
|
||||||
|
<div class="container" layout:fragment="content" style="margin-top: 70px">
|
||||||
|
Login: <p th:text="${userDto.getLogin()}"></p>
|
||||||
|
Имя: <p th:text="${userDto.getFirstName()}"></p>
|
||||||
|
Фамилия: <p th:text="${userDto.getLastName()}"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</html>
|
@ -1,5 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="ru"
|
<html lang="ru" data-framework="javascript"
|
||||||
|
xmlns:th="http://www.thymeleaf.org"
|
||||||
|
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||||
<head>
|
<head>
|
||||||
|
|
||||||
@ -20,6 +22,7 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="/css/google/kaushan.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/google/kaushan.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/css/google/droid.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/google/droid.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/css/google/roboto.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/google/roboto.css"/>
|
||||||
|
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"/>
|
||||||
|
|
||||||
<!-- Custom styles for this template -->
|
<!-- Custom styles for this template -->
|
||||||
<link rel="stylesheet" href="/css/agency.css"/>
|
<link rel="stylesheet" href="/css/agency.css"/>
|
||||||
@ -36,33 +39,35 @@
|
|||||||
<body id="page-top">
|
<body id="page-top">
|
||||||
|
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="navbar navbar-expand-lg navbar-dark fixed-top navbar-shrink" id="mainNav">
|
<div class="isAuth" sec:authorize="isAuthenticated()" style="display: none" sec:authentication="name"></div>
|
||||||
<div class="container">
|
<div id="react-navbar"></div>
|
||||||
<a class="navbar-brand js-scroll-trigger" href="/">NG-Tracker</a>
|
<!--<nav class="navbar navbar-expand-lg navbar-dark fixed-top navbar-shrink" id="mainNav">-->
|
||||||
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse"
|
<!--<div class="container">-->
|
||||||
data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false"
|
<!--<a class="navbar-brand js-scroll-trigger" href="/">NG-Tracker</a>-->
|
||||||
aria-label="Toggle navigation">
|
<!--<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse"-->
|
||||||
Menu
|
<!--data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false"-->
|
||||||
<i class="fa fa-bars"></i>
|
<!--aria-label="Toggle navigation">-->
|
||||||
</button>
|
<!--Menu-->
|
||||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
<!--<i class="fa fa-bars"></i>-->
|
||||||
<ul class="navbar-nav text-uppercase ml-auto">
|
<!--</button>-->
|
||||||
<li class="nav-item">
|
<!--<div class="collapse navbar-collapse" id="navbarResponsive">-->
|
||||||
<a class="nav-link js-scroll-trigger" target="_blank" href="#landing">НИО-17</a>
|
<!--<ul class="navbar-nav text-uppercase ml-auto">-->
|
||||||
</li>
|
<!--<li class="nav-item">-->
|
||||||
<li class="nav-item">
|
<!--<a class="nav-link js-scroll-trigger" target="_blank" href="#landing">НИО-17</a>-->
|
||||||
<a class="nav-link js-scroll-trigger" target="_blank" href="http://is.ulstu.ru">Сайт кафедры</a>
|
<!--</li>-->
|
||||||
</li>
|
<!--<li class="nav-item">-->
|
||||||
<li class="nav-item">
|
<!--<a class="nav-link js-scroll-trigger" target="_blank" href="http://is.ulstu.ru">Сайт кафедры</a>-->
|
||||||
<a class="nav-link js-scroll-trigger" target="_blank" href="https://kias.rfbr.ru/">КИАС РФФИ</a>
|
<!--</li>-->
|
||||||
</li>
|
<!--<li class="nav-item">-->
|
||||||
<li class="nav-item">
|
<!--<a class="nav-link js-scroll-trigger" target="_blank" href="https://kias.rfbr.ru/">КИАС РФФИ</a>-->
|
||||||
<a class="nav-link js-scroll-trigger" href="#logout">Выход</a>
|
<!--</li>-->
|
||||||
</li>
|
<!--<li class="nav-item" sec:authorize="isAuthenticated()">-->
|
||||||
</ul>
|
<!--<a class="nav-link js-scroll-trigger" href="/logout">Выход</a>-->
|
||||||
</div>
|
<!--</li>-->
|
||||||
</div>
|
<!--</ul>-->
|
||||||
</nav>
|
<!--</div>-->
|
||||||
|
<!--</div>-->
|
||||||
|
<!--</nav>-->
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<ul id="messages" class="feedback-panel">
|
<ul id="messages" class="feedback-panel">
|
||||||
@ -91,6 +96,19 @@
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="/js/core.js"></script>
|
<script src="/js/core.js"></script>
|
||||||
|
|
||||||
|
<!-- React -->
|
||||||
|
<script src="/webjars/react/16.7.0/umd/react.production.min.js"></script>
|
||||||
|
<script src="/webjars/react-dom/16.7.0/umd/react-dom.production.min.js"></script>
|
||||||
|
<script src="/webjars/material-ui__core/3.5.1/umd/material-ui.production.min.js"></script>
|
||||||
|
<script src="/webjars/prop-types/15.6.2/prop-types.min.js"></script>
|
||||||
|
<script src="/webjars/babel-standalone/6.26.0/babel.min.js"></script>
|
||||||
|
<div id="react-scripts">
|
||||||
|
<div layout:fragment="react-scripts"></div>
|
||||||
|
<script type="text/babel" src="/js/react/mainPage/navbar.js"></script>
|
||||||
|
</div>
|
||||||
|
<!-- /React -->
|
||||||
|
|
||||||
<!-- Yandex.Metrika counter -->
|
<!-- Yandex.Metrika counter -->
|
||||||
<script type="text/javascript" >
|
<script type="text/javascript" >
|
||||||
(function (d, w, c) {
|
(function (d, w, c) {
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en"
|
<html lang="en"
|
||||||
xmlns:th="http://www.thymeleaf.org"
|
xmlns:th="http://www.thymeleaf.org"
|
||||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
|
||||||
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||||
|
layout:decorator="default">
|
||||||
<head>
|
<head>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -12,105 +14,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="container" layout:fragment="content">
|
<div class="container" layout:fragment="content">
|
||||||
<ul class="nav nav-tabs">
|
<div class="isAuth" sec:authorize="isAuthenticated()" style="display: none"></div>
|
||||||
<li class="active"><a href="#signin">Вход в систему</a></li>
|
<section id="loginForm">
|
||||||
<li><a href="#register">Регистрация</a></li>
|
</section>
|
||||||
</ul>
|
</div>
|
||||||
<div class="tab-content">
|
|
||||||
<div id="signin" class="tab-pane active">
|
<div layout:fragment="react-scripts" th:remove="tag">
|
||||||
<form th:action="@{/login}" method="post" class="margined-top-10">
|
<script type="text/babel" src="/js/react/loginPage/components/login.js"></script>
|
||||||
<fieldset>
|
<script type="text/babel" src="/js/react/loginPage/components/register.js"></script>
|
||||||
<div class="form-group">
|
<script type="text/babel" src="/js/react/loginPage/index.js"></script>
|
||||||
<input type="text" name="username" id="username" class="form-control"
|
|
||||||
placeholder="Логин" required="true" autofocus="true"/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
|
||||||
<input type="password" name="password" id="password" class="form-control"
|
|
||||||
placeholder="Пароль" required="true"/>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-success btn-block">Войти</button>
|
|
||||||
<div class="form-group">
|
|
||||||
<small class="form-text text-muted">
|
|
||||||
<a href="/resetRequest">Забыли пароль?</a>
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div id="register" class="tab-pane">
|
|
||||||
<form id="register-form" class="margined-top-10">
|
|
||||||
<fieldset>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" name="login" id="login" class="form-control"
|
|
||||||
placeholder="Логин" required="true" autofocus="true"
|
|
||||||
minlength="4" maxlength="50"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" name="firstName" id="firstName" class="form-control"
|
|
||||||
placeholder="Имя" required="true" autofocus="true"
|
|
||||||
minlength="2" maxlength="50"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" name="lastName" id="lastName" class="form-control"
|
|
||||||
placeholder="Фамилия" required="true" autofocus="true"
|
|
||||||
minlength="2" maxlength="50"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="text" name="email" id="email" class="form-control"
|
|
||||||
placeholder="E-Mail" required="true" autofocus="true"
|
|
||||||
minlength="5" maxlength="100"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="password" name="password" id="password1" class="form-control"
|
|
||||||
placeholder="Пароль" required="true" maxlength="50"/>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<input type="password" name="passwordConfirm" id="password2" class="form-control"
|
|
||||||
placeholder="Пароль (подтверждение)" required="true" maxlength="50"/>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-info btn-block">Создать запись</button>
|
|
||||||
</fieldset>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<th:block layout:fragment="data-scripts">
|
|
||||||
<script type="text/javascript">
|
|
||||||
/*<![CDATA[*/
|
|
||||||
$(document).ready(function () {
|
|
||||||
if (isUrlVarExists('error')) {
|
|
||||||
showFeedbackMessage('Ошибка входа в систему', 'danger');
|
|
||||||
}
|
|
||||||
if (isUrlVarExists('logout')) {
|
|
||||||
showFeedbackMessage('Выход из системы произведен');
|
|
||||||
}
|
|
||||||
registerFormToJson = function () {
|
|
||||||
var 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);
|
|
||||||
};
|
|
||||||
registerUser = function () {
|
|
||||||
postToRest(urlUsersRegister, registerFormToJson(), function (data) {
|
|
||||||
showFeedbackMessage("Пользователь успешно создан");
|
|
||||||
$("#register-form").find(":input").not(":button").val("");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
$("#register-form").submit(function () {
|
|
||||||
registerUser();
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
/*]]>*/
|
|
||||||
|
|
||||||
</script>
|
|
||||||
</th:block>
|
|
||||||
<th:block layout:fragment="scripts">
|
|
||||||
<script src="/js/hashable-tabs.js"></script>
|
|
||||||
</th:block>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user