Add custom error page, add profile settings page '/profile/'
This commit is contained in:
parent
147f590410
commit
bb6059d63e
28 changed files with 401 additions and 35 deletions
|
@ -1,11 +1,13 @@
|
|||
package ru.redrise.marinesco;
|
||||
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
//@PreAuthorize("hasRole('USER')")
|
||||
@Controller
|
||||
public class RootController {
|
||||
|
||||
|
||||
@GetMapping("/")
|
||||
public String home(){
|
||||
return "root";
|
||||
|
|
|
@ -7,6 +7,7 @@ import org.springframework.boot.ApplicationArguments;
|
|||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ru.redrise.marinesco.data.RolesRepository;
|
||||
|
@ -25,13 +26,14 @@ public class ShinyApplicationRunner {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public ApplicationRunner appRunner() {
|
||||
public ApplicationRunner appRunner(PasswordEncoder encoder) {
|
||||
return args -> {
|
||||
if (isFirstRun()) {
|
||||
log.info("Application first run");
|
||||
setRoles();
|
||||
setAdmin(args);
|
||||
setAdmin(args, encoder);
|
||||
} else
|
||||
log.info("NOT FIRST APPLICATION RUN; DB Already set up");
|
||||
log.info("Regular run");
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -45,7 +47,7 @@ public class ShinyApplicationRunner {
|
|||
new UserRole(null, "User", UserRole.Type.USER)));
|
||||
}
|
||||
|
||||
private void setAdmin(ApplicationArguments args) {
|
||||
private void setAdmin(ApplicationArguments args, PasswordEncoder encoder) {
|
||||
List<String> login = args.getOptionValues("admin_login");
|
||||
List<String> password = args.getOptionValues("admin_password");
|
||||
|
||||
|
@ -53,10 +55,11 @@ public class ShinyApplicationRunner {
|
|||
|
||||
if (login == null || login.size() == 0 || password == null || password.size() == 0) {
|
||||
log.warn("No administrator credentials provided, using defaults:\n * Login: root\n * Password: root\n Expected: --admin_login LOGIN --admin_password PASSWORD "); // TODO: Move into properties i18n
|
||||
var adminUser = new User("root", "root", "SuperAdmin", adminRoleOnlyAthority);
|
||||
var adminUser = new User("root", encoder.encode("root"), "SuperAdmin", adminRoleOnlyAthority);
|
||||
users.save(adminUser);
|
||||
return;
|
||||
}
|
||||
users.save(new User(login.get(0), password.get(0), "SuperAdmin", adminRoleOnlyAthority));
|
||||
log.info("SuperAdmin role created\n * Login: {}", login.get(0));
|
||||
users.save(new User(login.get(0), encoder.encode(password.get(0)), "SuperAdmin", adminRoleOnlyAthority));
|
||||
}
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
package ru.redrise.marinesco;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.FetchType;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
|
@ -14,14 +15,12 @@ import jakarta.persistence.Table;
|
|||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import ru.redrise.marinesco.security.UserRole;
|
||||
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "\"USER\"")
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
|
||||
@RequiredArgsConstructor
|
||||
public class User implements UserDetails{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -29,14 +28,21 @@ public class User implements UserDetails{
|
|||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
|
||||
private final String username;
|
||||
private final String password;
|
||||
private final String displayname;
|
||||
|
||||
@ManyToMany
|
||||
private final List<UserRole> authorities;
|
||||
|
||||
private final String username;
|
||||
private String password;
|
||||
private String displayname;
|
||||
|
||||
@ManyToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER)
|
||||
private final List<UserRole> authorities;
|
||||
|
||||
public User(String username, String password, String displayname, List<UserRole> authorities){
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.displayname = displayname;
|
||||
this.authorities = authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return true;
|
||||
|
|
23
src/main/java/ru/redrise/marinesco/UserSettingsForm.java
Normal file
23
src/main/java/ru/redrise/marinesco/UserSettingsForm.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package ru.redrise.marinesco;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class UserSettingsForm {
|
||||
|
||||
@NotNull
|
||||
@NotEmpty(message = "Display name could not be blank")
|
||||
public String displayname;
|
||||
public String newPassword;
|
||||
|
||||
public boolean isNewPasswordSet(){
|
||||
return ! newPassword.isBlank();
|
||||
}
|
||||
|
||||
public boolean isNewPasswordValid(){
|
||||
final int newPasswordLength = newPassword.length();
|
||||
return newPasswordLength > 8 && newPasswordLength < 32;
|
||||
}
|
||||
}
|
|
@ -2,10 +2,14 @@ package ru.redrise.marinesco.security;
|
|||
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import ru.redrise.marinesco.data.RolesRepository;
|
||||
import ru.redrise.marinesco.data.UserRepository;
|
||||
|
||||
|
@ -16,20 +20,33 @@ public class RegistrationController {
|
|||
private RolesRepository rolesRepo;
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
public RegistrationController(UserRepository userRepo, RolesRepository rolesRepo, PasswordEncoder passwordEncoder){
|
||||
public RegistrationController(UserRepository userRepo, RolesRepository rolesRepo, PasswordEncoder passwordEncoder) {
|
||||
this.userRepo = userRepo;
|
||||
this.rolesRepo = rolesRepo;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
@ModelAttribute(name = "registrationForm")
|
||||
public RegistrationForm form() {
|
||||
return new RegistrationForm();
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String registerForm(){
|
||||
public String registerForm() {
|
||||
return "registration";
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public String postMethodName(RegistrationForm registrationForm) {
|
||||
userRepo.save(registrationForm.toUser(passwordEncoder, rolesRepo));
|
||||
public String postMethodName(@Valid RegistrationForm registerForm, Errors errors, Model model) {
|
||||
if (registerForm.isPasswordsNotEqual()){
|
||||
model.addAttribute("passwordsMismatch", "Passwords must be the same.");
|
||||
return "registration";
|
||||
}
|
||||
if (errors.hasErrors()) {
|
||||
return "registration";
|
||||
}
|
||||
|
||||
userRepo.save(registerForm.toUser(passwordEncoder, rolesRepo));
|
||||
return "redirect:/login";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,20 +2,28 @@ package ru.redrise.marinesco.security;
|
|||
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import ru.redrise.marinesco.User;
|
||||
import ru.redrise.marinesco.data.RolesRepository;
|
||||
|
||||
@Data
|
||||
public class RegistrationForm {
|
||||
|
||||
@NotNull
|
||||
@Size(min=3, max=32, message="Username must be at least 3 characters long. Should not exceed 32 characters.")
|
||||
private String username;
|
||||
|
||||
@NotNull
|
||||
@Size(min=8, max = 32, message="Password must be at least 8 characters long. Should not exceed 32 characters.")
|
||||
private String password;
|
||||
|
||||
private String passwordConfirm;
|
||||
|
||||
@NotNull
|
||||
private String fullname;
|
||||
@NotNull
|
||||
@NotEmpty(message = "Display name could not be blank")
|
||||
private String displayname;
|
||||
|
||||
public User toUser(PasswordEncoder passwordEncoder, RolesRepository rolesRepo){
|
||||
|
@ -25,4 +33,7 @@ public class RegistrationForm {
|
|||
displayname,
|
||||
rolesRepo.findByType(UserRole.Type.USER));
|
||||
}
|
||||
public boolean isPasswordsNotEqual(){
|
||||
return ! password.equals(passwordConfirm);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,19 +45,25 @@ public class SecurityConfig {
|
|||
public SecurityFilterChain filterChain(HttpSecurity http, MvcRequestMatcher.Builder mvc) throws Exception {
|
||||
return http
|
||||
.authorizeHttpRequests(autorize -> autorize
|
||||
.requestMatchers(mvc.pattern("/favicon.ico")).permitAll()
|
||||
.requestMatchers(mvc.pattern("/jquery.js")).permitAll()
|
||||
.requestMatchers(mvc.pattern("/styles/**")).permitAll()
|
||||
.requestMatchers(mvc.pattern("/images/*")).permitAll()
|
||||
.requestMatchers(mvc.pattern("/register")).permitAll()
|
||||
.requestMatchers(mvc.pattern("/login")).permitAll()
|
||||
.requestMatchers(mvc.pattern("/error")).permitAll()
|
||||
.requestMatchers(mvc.pattern("/")).hasAnyRole("ADMIN", "USER")
|
||||
.requestMatchers(mvc.pattern("/profile/**")).hasAnyRole("ADMIN", "USER")
|
||||
.requestMatchers(PathRequest.toH2Console()).permitAll()
|
||||
//.requestMatchers(mvc.pattern("/design/**")).hasRole("USER")
|
||||
.anyRequest().denyAll())
|
||||
//.anyRequest().permitAll())
|
||||
.formLogin(formLoginConfigurer -> formLoginConfigurer
|
||||
.loginPage("/login")
|
||||
.loginProcessingUrl("/auth")
|
||||
//.loginProcessingUrl("/auth")
|
||||
.usernameParameter("login")
|
||||
.passwordParameter("pwd")
|
||||
//.defaultSuccessUrl("/", true)
|
||||
.defaultSuccessUrl("/")
|
||||
)
|
||||
// .formLogin(Customizer.withDefaults())
|
||||
//.oauth2Login(c -> c.loginPage("/login"))
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package ru.redrise.marinesco.security;
|
||||
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import ru.redrise.marinesco.User;
|
||||
import ru.redrise.marinesco.UserSettingsForm;
|
||||
import ru.redrise.marinesco.data.UserRepository;
|
||||
|
||||
@Slf4j
|
||||
@Controller
|
||||
@RequestMapping("/profile")
|
||||
public class UserSettingsController {
|
||||
private final UserRepository userRepo;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
public UserSettingsController(UserRepository userRepo, PasswordEncoder passwordEncoder){
|
||||
this.userRepo = userRepo;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
@ModelAttribute
|
||||
public void addMisc(Model model, @AuthenticationPrincipal User user){
|
||||
final String displayName = user.getDisplayname();
|
||||
model.addAttribute("header_text", "Welcome " + displayName);
|
||||
|
||||
UserSettingsForm form = new UserSettingsForm();
|
||||
form.setDisplayname(displayName);
|
||||
model.addAttribute( "userSettingsForm", form);
|
||||
}
|
||||
|
||||
@ModelAttribute
|
||||
public UserSettingsForm addSettingsForm(){
|
||||
return new UserSettingsForm();
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String getPage(){
|
||||
return "redirect:/profile/settings";
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/settings")
|
||||
public String getSettingsFirstPage(){
|
||||
return "user_settings";
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/settings")
|
||||
public String getSettingsPage(@Valid UserSettingsForm userSettingsForm,
|
||||
Errors errors,
|
||||
@AuthenticationPrincipal User user,
|
||||
Model model){
|
||||
if (errors.hasErrors())
|
||||
return "user_settings";
|
||||
if (! user.getDisplayname().equals(userSettingsForm.getDisplayname()))
|
||||
user.setDisplayname(userSettingsForm.getDisplayname());
|
||||
if (userSettingsForm.isNewPasswordSet()){
|
||||
if (userSettingsForm.isNewPasswordValid()){
|
||||
user.setPassword(passwordEncoder.encode(userSettingsForm.getNewPassword()));
|
||||
}
|
||||
else{
|
||||
model.addAttribute("password_incorrect", "Password must be at least 8 characters long. Should not exceed 32 characters.");
|
||||
return "user_settings";
|
||||
}
|
||||
}
|
||||
|
||||
log.info("{} {}", userSettingsForm.getDisplayname(), userSettingsForm.getNewPassword());
|
||||
userRepo.save(user);
|
||||
|
||||
return "user_settings";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
package ru.redrise.marinesco.web;
|
||||
|
||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
||||
@Controller
|
||||
public class HandyErrorController implements ErrorController{
|
||||
|
||||
@ModelAttribute(name = "code")
|
||||
public String addMisc(HttpServletRequest request){
|
||||
return request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE).toString();
|
||||
}
|
||||
|
||||
@RequestMapping("/error")
|
||||
public String handleError(){
|
||||
return "error";
|
||||
}
|
||||
}
|
2
src/main/resources/static/jquery.js
vendored
Normal file
2
src/main/resources/static/jquery.js
vendored
Normal file
File diff suppressed because one or more lines are too long
53
src/main/resources/templates/error.html
Normal file
53
src/main/resources/templates/error.html
Normal file
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<style type=text/css>
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #212121;
|
||||
color: #cfcfcf;
|
||||
font-family: Terminus;
|
||||
}
|
||||
|
||||
.error {
|
||||
border-width: 3px;
|
||||
border-style: double;
|
||||
padding: 8px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.bli {
|
||||
padding: 3px;
|
||||
background-color: #D00000;
|
||||
animation: blinker 2.5s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes blinker {
|
||||
50% {
|
||||
opacity: 0.0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<title th:text="${code}">title</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class='error'>
|
||||
ОШИБКА: <span class='bli' th:text="${code}"></span>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -16,6 +16,7 @@
|
|||
<br /><a href="/h2">H2</a>
|
||||
<form class="form-signin" method="post" action="/login">
|
||||
<h2 class="form-signin-heading">Please sign in</h2>
|
||||
<br /><span class="validationError" th:if="${param.error}">Unable to login. Check your username and password.</span>
|
||||
<p>
|
||||
<label for="username" class="sr-only">Username</label>
|
||||
<input type="text" id="username" name="login" class="form-control" placeholder="Username" required autofocus>
|
||||
|
|
|
@ -5,20 +5,34 @@
|
|||
<title>Marinesco - registration form</title>
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
|
||||
<script src="@{/jquery.js}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Register</h1>
|
||||
<img th:src="@{/images/logo.svg}" />
|
||||
<form method="POST" th:action="@{/register}" id="registerForm">
|
||||
<form class="regForm" method="POST" th:action="@{/register}" th:object="${registrationForm}">
|
||||
|
||||
<span class="validationError" th:if="${#fields.hasErrors('username')}" th:errors="*{username}">Error</span>
|
||||
<br />
|
||||
<label for="username">Username: </label>
|
||||
<input type="text" name="login" /><br />
|
||||
<input type="text" name="username" id="username"/><br />
|
||||
|
||||
<span class="validationError" th:if="${#fields.hasErrors('password')}" th:errors="*{password}">Error</span>
|
||||
<br />
|
||||
<label for="password">Password: </label>
|
||||
<input type="password" name="pwd" /><br />
|
||||
<input type="password" name="password" id="password"/><br />
|
||||
|
||||
<span class="validationError" th:if="${passwordsMismatch} != null" th:text="${passwordsMismatch}">false</span>
|
||||
<br />
|
||||
<label for="confirm">Confirm password: </label>
|
||||
<input type="password" name="confirm" /><br />
|
||||
<input type="password" name="passwordConfirm" id="passwordConfirm" /><br />
|
||||
|
||||
<span class="validationError" th:if="${#fields.hasErrors('displayname')}" th:errors="*{displayname}">Error</span>
|
||||
<br />
|
||||
<label for="displayname">Displayed name: </label>
|
||||
<input type="text" name="fullname" /><br />
|
||||
<input type="text" name="displayname" id="displayname"/><br />
|
||||
|
||||
<input type="submit" value="Register" />
|
||||
</form>
|
||||
</body>
|
||||
|
|
26
src/main/resources/templates/user_settings.html
Normal file
26
src/main/resources/templates/user_settings.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<title>Marinesco - Profile settings</title>
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 th:text="${header_text}">welcome</h1>
|
||||
<form method="POST" th:action="@{/profile/settings}" th:object="${userSettingsForm}"> <!-- -->
|
||||
<span class="validationError" th:if="${#fields.hasErrors('displayname')}" th:errors="*{displayname}">Error</span>
|
||||
<br />
|
||||
<label for="displayname">Displayed name: </label>
|
||||
<input type="text" name="displayname" id="displayname" th:value="${userSettingsForm.displayname}" /><br />
|
||||
|
||||
<span class="validationError" th:if="${password_incorrect} != null" th:text="${password_incorrect}">false</span>
|
||||
<br />
|
||||
<label for="password">New password: </label>
|
||||
<input type="password" name="newPassword" id="newPassword" /><br />
|
||||
|
||||
<input type="submit" value="Save Changes" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
target/classes/ru/redrise/marinesco/UserSettingsForm.class
Normal file
BIN
target/classes/ru/redrise/marinesco/UserSettingsForm.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2
target/classes/static/jquery.js
vendored
Normal file
2
target/classes/static/jquery.js
vendored
Normal file
File diff suppressed because one or more lines are too long
53
target/classes/templates/error.html
Normal file
53
target/classes/templates/error.html
Normal file
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<style type=text/css>
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #212121;
|
||||
color: #cfcfcf;
|
||||
font-family: Terminus;
|
||||
}
|
||||
|
||||
.error {
|
||||
border-width: 3px;
|
||||
border-style: double;
|
||||
padding: 8px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.bli {
|
||||
padding: 3px;
|
||||
background-color: #D00000;
|
||||
animation: blinker 2.5s ease infinite;
|
||||
}
|
||||
|
||||
@keyframes blinker {
|
||||
50% {
|
||||
opacity: 0.0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<title th:text="${code}">title</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class='error'>
|
||||
ОШИБКА: <span class='bli' th:text="${code}"></span>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -16,6 +16,7 @@
|
|||
<br /><a href="/h2">H2</a>
|
||||
<form class="form-signin" method="post" action="/login">
|
||||
<h2 class="form-signin-heading">Please sign in</h2>
|
||||
<br /><span class="validationError" th:if="${param.error}">Unable to login. Check your username and password.</span>
|
||||
<p>
|
||||
<label for="username" class="sr-only">Username</label>
|
||||
<input type="text" id="username" name="login" class="form-control" placeholder="Username" required autofocus>
|
||||
|
|
|
@ -5,20 +5,34 @@
|
|||
<title>Marinesco - registration form</title>
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
|
||||
<script src="@{/jquery.js}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Register</h1>
|
||||
<img th:src="@{/images/logo.svg}" />
|
||||
<form method="POST" th:action="@{/register}" id="registerForm">
|
||||
<form class="regForm" method="POST" th:action="@{/register}" th:object="${registrationForm}">
|
||||
|
||||
<span class="validationError" th:if="${#fields.hasErrors('username')}" th:errors="*{username}">Error</span>
|
||||
<br />
|
||||
<label for="username">Username: </label>
|
||||
<input type="text" name="login" /><br />
|
||||
<input type="text" name="username" id="username"/><br />
|
||||
|
||||
<span class="validationError" th:if="${#fields.hasErrors('password')}" th:errors="*{password}">Error</span>
|
||||
<br />
|
||||
<label for="password">Password: </label>
|
||||
<input type="password" name="pwd" /><br />
|
||||
<input type="password" name="password" id="password"/><br />
|
||||
|
||||
<span class="validationError" th:if="${passwordsMismatch} != null" th:text="${passwordsMismatch}">false</span>
|
||||
<br />
|
||||
<label for="confirm">Confirm password: </label>
|
||||
<input type="password" name="confirm" /><br />
|
||||
<input type="password" name="passwordConfirm" id="passwordConfirm" /><br />
|
||||
|
||||
<span class="validationError" th:if="${#fields.hasErrors('displayname')}" th:errors="*{displayname}">Error</span>
|
||||
<br />
|
||||
<label for="displayname">Displayed name: </label>
|
||||
<input type="text" name="fullname" /><br />
|
||||
<input type="text" name="displayname" id="displayname"/><br />
|
||||
|
||||
<input type="submit" value="Register" />
|
||||
</form>
|
||||
</body>
|
||||
|
|
26
target/classes/templates/user_settings.html
Normal file
26
target/classes/templates/user_settings.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<title>Marinesco - Profile settings</title>
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" th:href="@{/styles/styles.css}" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 th:text="${header_text}">welcome</h1>
|
||||
<form method="POST" th:action="@{/profile/settings}" th:object="${userSettingsForm}"> <!-- -->
|
||||
<span class="validationError" th:if="${#fields.hasErrors('displayname')}" th:errors="*{displayname}">Error</span>
|
||||
<br />
|
||||
<label for="displayname">Displayed name: </label>
|
||||
<input type="text" name="displayname" id="displayname" th:value="${userSettingsForm.displayname}" /><br />
|
||||
|
||||
<span class="validationError" th:if="${password_incorrect} != null" th:text="${password_incorrect}">false</span>
|
||||
<br />
|
||||
<label for="password">New password: </label>
|
||||
<input type="password" name="newPassword" id="newPassword" /><br />
|
||||
|
||||
<input type="submit" value="Save Changes" />
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue