Lab6: MVC side authentication is done
This commit is contained in:
parent
5af0868021
commit
c1a2e77e4d
@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id 'org.springframework.boot' version '3.0.2'
|
id 'org.springframework.boot' version '2.6.3'
|
||||||
id 'io.spring.dependency-management' version '1.1.0'
|
id 'io.spring.dependency-management' version '1.1.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,6 +22,9 @@ dependencies {
|
|||||||
implementation 'org.webjars:bootstrap:5.1.3'
|
implementation 'org.webjars:bootstrap:5.1.3'
|
||||||
implementation 'org.webjars:jquery:3.6.0'
|
implementation 'org.webjars:jquery:3.6.0'
|
||||||
implementation 'org.webjars:font-awesome:6.1.0'
|
implementation 'org.webjars:font-awesome:6.1.0'
|
||||||
|
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||||
|
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
|
||||||
|
implementation 'com.auth0:java-jwt:4.4.0'
|
||||||
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5'
|
implementation group: 'org.springdoc', name: 'springdoc-openapi-ui', version: '1.6.5'
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
implementation 'org.hibernate.validator:hibernate-validator'
|
implementation 'org.hibernate.validator:hibernate-validator'
|
||||||
|
29
src/main/java/np/something/DTO/UserSignupDto.java
Normal file
29
src/main/java/np/something/DTO/UserSignupDto.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package np.something.DTO;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
public class UserSignupDto {
|
||||||
|
@NotBlank
|
||||||
|
@Size(min = 3, max = 64)
|
||||||
|
private String username;
|
||||||
|
@NotBlank
|
||||||
|
@Size(min = 6, max = 64)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
}
|
@ -2,12 +2,19 @@ package np.something;
|
|||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class WebConfiguration implements WebMvcConfigurer {
|
public class WebConfiguration implements WebMvcConfigurer {
|
||||||
public static final String REST_API = "/api";
|
public static final String REST_API = "/api";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addViewControllers(ViewControllerRegistry registry) {
|
||||||
|
WebMvcConfigurer.super.addViewControllers(registry);
|
||||||
|
registry.addViewController("login");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
public void addCorsMappings(CorsRegistry registry) {
|
||||||
registry.addMapping("/**").allowedMethods("*");
|
registry.addMapping("/**").allowedMethods("*");
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package np.something.controllers;
|
package np.something.controllers;
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import np.something.DTO.CommentDto;
|
import np.something.DTO.CommentDto;
|
||||||
import np.something.WebConfiguration;
|
import np.something.WebConfiguration;
|
||||||
import np.something.model.Comment;
|
import np.something.model.Comment;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package np.something.controllers;
|
package np.something.controllers;
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import np.something.DTO.CustomerDto;
|
import np.something.DTO.CustomerDto;
|
||||||
import np.something.WebConfiguration;
|
import np.something.WebConfiguration;
|
||||||
import np.something.model.Customer;
|
import np.something.model.Customer;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package np.something.controllers;
|
package np.something.controllers;
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import np.something.DTO.PostDto;
|
import np.something.DTO.PostDto;
|
||||||
import np.something.WebConfiguration;
|
import np.something.WebConfiguration;
|
||||||
import np.something.services.CustomerService;
|
import np.something.services.CustomerService;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package np.something.model;
|
package np.something.model;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import javax.persistence.*;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package np.something.model;
|
package np.something.model;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import org.h2.engine.User;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@ -21,6 +23,8 @@ public class Customer {
|
|||||||
@OneToMany(fetch = FetchType.EAGER, mappedBy = "customer", cascade = CascadeType.ALL)
|
@OneToMany(fetch = FetchType.EAGER, mappedBy = "customer", cascade = CascadeType.ALL)
|
||||||
private List<Post> posts;
|
private List<Post> posts;
|
||||||
|
|
||||||
|
private UserRole role;
|
||||||
|
|
||||||
public Customer() {
|
public Customer() {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -28,6 +32,15 @@ public class Customer {
|
|||||||
public Customer(String username, String password) {
|
public Customer(String username, String password) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
|
this.role = UserRole.USER;
|
||||||
|
this.comments = new ArrayList<>();
|
||||||
|
this.posts = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer(String username, String password, UserRole role) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
this.role = role;
|
||||||
this.comments = new ArrayList<>();
|
this.comments = new ArrayList<>();
|
||||||
this.posts = new ArrayList<>();
|
this.posts = new ArrayList<>();
|
||||||
}
|
}
|
||||||
@ -60,6 +73,10 @@ public class Customer {
|
|||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UserRole getRole() {
|
||||||
|
return role;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) return true;
|
if (this == obj) return true;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package np.something.model;
|
package np.something.model;
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
import javax.persistence.*;
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
20
src/main/java/np/something/model/UserRole.java
Normal file
20
src/main/java/np/something/model/UserRole.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package np.something.model;
|
||||||
|
|
||||||
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
||||||
|
public enum UserRole implements GrantedAuthority {
|
||||||
|
ADMIN,
|
||||||
|
USER;
|
||||||
|
|
||||||
|
private static final String PREFIX = "ROLE_";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAuthority() {
|
||||||
|
return PREFIX + this.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class AsString {
|
||||||
|
public static final String ADMIN = PREFIX + "ADMIN";
|
||||||
|
public static final String USER = PREFIX + "USER";
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,14 @@
|
|||||||
package np.something.mvc;
|
package np.something.mvc;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import jakarta.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import np.something.DTO.CustomerDto;
|
import np.something.DTO.CustomerDto;
|
||||||
|
import np.something.model.UserRole;
|
||||||
import np.something.services.CustomerService;
|
import np.something.services.CustomerService;
|
||||||
|
import org.springframework.security.access.annotation.Secured;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
@ -20,9 +24,12 @@ public class Admin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = { "/", "/{id}" })
|
@GetMapping(value = { "/", "/{id}" })
|
||||||
public String getCustomers(@PathVariable(required = false) Long id, HttpServletRequest request, HttpSession session, Model model) {
|
@Secured({UserRole.AsString.ADMIN})
|
||||||
|
public String getCustomers(@PathVariable(required = false) Long id, HttpServletRequest request, Model model) {
|
||||||
model.addAttribute("request", request);
|
model.addAttribute("request", request);
|
||||||
model.addAttribute("session", session);
|
model.addAttribute("currentCustomerId", customerService.findByUsername(
|
||||||
|
((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()
|
||||||
|
).getId());
|
||||||
if (id == null || id <= 0) {
|
if (id == null || id <= 0) {
|
||||||
model.addAttribute("customers", customerService.findAllCustomers().stream().map(CustomerDto::new).toList());
|
model.addAttribute("customers", customerService.findAllCustomers().stream().map(CustomerDto::new).toList());
|
||||||
return "admin";
|
return "admin";
|
||||||
@ -32,19 +39,20 @@ public class Admin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/delete/{id}")
|
@PostMapping("/delete/{id}")
|
||||||
public String deleteCustomer(@PathVariable Long id, HttpSession session) {
|
public String deleteCustomer(@PathVariable Long id) {
|
||||||
session.setAttribute("currentCustomerId", -1);
|
|
||||||
customerService.deleteCustomer(id);
|
customerService.deleteCustomer(id);
|
||||||
return "redirect:/admin/";
|
return "redirect:/admin/";
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping(value = { "/", "/{id}"})
|
@PostMapping(value = { "/", "/{id}"})
|
||||||
public String manipulateCustomer(@PathVariable(required = false) Long id, @ModelAttribute @Valid CustomerDto customerDto,
|
public String manipulateCustomer(@PathVariable(required = false) Long id, @ModelAttribute @Valid CustomerDto customerDto,
|
||||||
HttpServletRequest request, HttpSession session,
|
HttpServletRequest request,
|
||||||
BindingResult bindingResult,
|
BindingResult bindingResult,
|
||||||
Model model) {
|
Model model) {
|
||||||
model.addAttribute("request", request);
|
model.addAttribute("request", request);
|
||||||
model.addAttribute("session", session);
|
model.addAttribute("currentCustomerId", customerService.findByUsername(
|
||||||
|
((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()
|
||||||
|
).getId());
|
||||||
if (bindingResult.hasErrors()) {
|
if (bindingResult.hasErrors()) {
|
||||||
model.addAttribute("errors", bindingResult.getAllErrors());
|
model.addAttribute("errors", bindingResult.getAllErrors());
|
||||||
return "/admin";
|
return "/admin";
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package np.something.mvc;
|
package np.something.mvc;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import jakarta.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import np.something.DTO.CommentDto;
|
import np.something.DTO.CommentDto;
|
||||||
import np.something.DTO.PostDto;
|
import np.something.DTO.PostDto;
|
||||||
import np.something.services.CommentService;
|
import np.something.services.CommentService;
|
||||||
import np.something.services.CustomerService;
|
import np.something.services.CustomerService;
|
||||||
import np.something.services.PostService;
|
import np.something.services.PostService;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
@ -28,9 +30,11 @@ public class Comments {
|
|||||||
|
|
||||||
@PostMapping(value = { "/", "/{id}"})
|
@PostMapping(value = { "/", "/{id}"})
|
||||||
public String manipulateComment(@PathVariable(required = false) Long id, @ModelAttribute @Valid CommentDto commentDto,
|
public String manipulateComment(@PathVariable(required = false) Long id, @ModelAttribute @Valid CommentDto commentDto,
|
||||||
HttpServletRequest request, HttpSession session, BindingResult bindingResult, Model model) {
|
HttpServletRequest request, BindingResult bindingResult, Model model) {
|
||||||
model.addAttribute("request", request);
|
model.addAttribute("request", request);
|
||||||
model.addAttribute("session", session);
|
model.addAttribute("currentCustomerId", customerService.findByUsername(
|
||||||
|
((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()
|
||||||
|
).getId());
|
||||||
model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList());
|
model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList());
|
||||||
|
|
||||||
if (bindingResult.hasErrors()) {
|
if (bindingResult.hasErrors()) {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package np.something.mvc;
|
package np.something.mvc;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import jakarta.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import np.something.DTO.CustomerDto;
|
import np.something.DTO.CustomerDto;
|
||||||
import np.something.services.CustomerService;
|
import np.something.services.CustomerService;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
@ -22,7 +24,9 @@ public class Customers {
|
|||||||
@GetMapping(value = { "/", "/{id}" })
|
@GetMapping(value = { "/", "/{id}" })
|
||||||
public String getCustomers(@PathVariable(required = false) Long id, HttpServletRequest request, HttpSession session, Model model) {
|
public String getCustomers(@PathVariable(required = false) Long id, HttpServletRequest request, HttpSession session, Model model) {
|
||||||
model.addAttribute("request", request);
|
model.addAttribute("request", request);
|
||||||
model.addAttribute("session", session);
|
model.addAttribute("currentCustomerId", customerService.findByUsername(
|
||||||
|
((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()
|
||||||
|
).getId());
|
||||||
if (id == null || id <= 0) {
|
if (id == null || id <= 0) {
|
||||||
model.addAttribute("customers", customerService.findAllCustomers().stream().map(CustomerDto::new).toList());
|
model.addAttribute("customers", customerService.findAllCustomers().stream().map(CustomerDto::new).toList());
|
||||||
} else {
|
} else {
|
||||||
@ -34,7 +38,6 @@ public class Customers {
|
|||||||
|
|
||||||
@PostMapping("/delete/{id}")
|
@PostMapping("/delete/{id}")
|
||||||
public String deleteCustomer(@PathVariable Long id, HttpSession session) {
|
public String deleteCustomer(@PathVariable Long id, HttpSession session) {
|
||||||
session.setAttribute("currentCustomerId", -1);
|
|
||||||
customerService.deleteCustomer(id);
|
customerService.deleteCustomer(id);
|
||||||
return "redirect:/customers/";
|
return "redirect:/customers/";
|
||||||
}
|
}
|
||||||
@ -45,7 +48,9 @@ public class Customers {
|
|||||||
BindingResult bindingResult,
|
BindingResult bindingResult,
|
||||||
Model model) {
|
Model model) {
|
||||||
model.addAttribute("request", request);
|
model.addAttribute("request", request);
|
||||||
model.addAttribute("session", session);
|
model.addAttribute("currentCustomerId", customerService.findByUsername(
|
||||||
|
((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()
|
||||||
|
).getId());
|
||||||
if (bindingResult.hasErrors()) {
|
if (bindingResult.hasErrors()) {
|
||||||
model.addAttribute("errors", bindingResult.getAllErrors());
|
model.addAttribute("errors", bindingResult.getAllErrors());
|
||||||
return "/customers";
|
return "/customers";
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package np.something.mvc;
|
package np.something.mvc;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import np.something.DTO.CommentDto;
|
import np.something.DTO.CommentDto;
|
||||||
import np.something.DTO.CustomerDto;
|
import np.something.DTO.CustomerDto;
|
||||||
import np.something.DTO.PostDto;
|
import np.something.DTO.PostDto;
|
||||||
@ -9,6 +9,8 @@ import np.something.model.Post;
|
|||||||
import np.something.services.CommentService;
|
import np.something.services.CommentService;
|
||||||
import np.something.services.CustomerService;
|
import np.something.services.CustomerService;
|
||||||
import np.something.services.PostService;
|
import np.something.services.PostService;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
@ -21,7 +23,7 @@ import java.util.List;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping("/feed")
|
@RequestMapping(value = { "", "/feed" })
|
||||||
public class Feed {
|
public class Feed {
|
||||||
private final PostService postService;
|
private final PostService postService;
|
||||||
private final CustomerService customerService;
|
private final CustomerService customerService;
|
||||||
@ -37,7 +39,9 @@ public class Feed {
|
|||||||
@GetMapping
|
@GetMapping
|
||||||
public String getPosts(@RequestParam(required = false) String search, HttpServletRequest request, HttpSession session, Model model) {
|
public String getPosts(@RequestParam(required = false) String search, HttpServletRequest request, HttpSession session, Model model) {
|
||||||
model.addAttribute("request", request);
|
model.addAttribute("request", request);
|
||||||
model.addAttribute("session", session);
|
model.addAttribute("currentCustomerId", customerService.findByUsername(
|
||||||
|
((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()
|
||||||
|
).getId());
|
||||||
if (search == null) {
|
if (search == null) {
|
||||||
model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList());
|
model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList());
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package np.something.mvc;
|
package np.something.mvc;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import np.something.services.CommentService;
|
import np.something.services.CommentService;
|
||||||
import np.something.services.CustomerService;
|
import np.something.services.CustomerService;
|
||||||
import np.something.services.PostService;
|
import np.something.services.PostService;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import jakarta.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import np.something.DTO.PostDto;
|
import np.something.DTO.PostDto;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@ -37,7 +39,9 @@ public class Posts {
|
|||||||
BindingResult bindingResult,
|
BindingResult bindingResult,
|
||||||
Model model) {
|
Model model) {
|
||||||
model.addAttribute("request", request);
|
model.addAttribute("request", request);
|
||||||
model.addAttribute("session", session);
|
model.addAttribute("currentCustomerId", customerService.findByUsername(
|
||||||
|
((UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername()
|
||||||
|
).getId());
|
||||||
model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList());
|
model.addAttribute("posts", postService.findAllPosts().stream().map(PostDto::new).toList());
|
||||||
|
|
||||||
if (bindingResult.hasErrors()) {
|
if (bindingResult.hasErrors()) {
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
package np.something.mvc;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpSession;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
|
|
||||||
@Controller
|
|
||||||
public class Session {
|
|
||||||
@PostMapping("/update-session")
|
|
||||||
public ResponseEntity<Void> updateSession(@RequestParam("currentCustomerId") int currentCustomerId, HttpSession session) {
|
|
||||||
session.setAttribute("currentCustomerId", currentCustomerId);
|
|
||||||
return ResponseEntity.ok().build();
|
|
||||||
}
|
|
||||||
}
|
|
53
src/main/java/np/something/mvc/UserSignUp.java
Normal file
53
src/main/java/np/something/mvc/UserSignUp.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package np.something.mvc;
|
||||||
|
|
||||||
|
import np.something.DTO.UserSignupDto;
|
||||||
|
import np.something.model.Customer;
|
||||||
|
import np.something.services.CustomerService;
|
||||||
|
import np.something.util.validation.ValidationException;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.validation.BindingResult;
|
||||||
|
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 javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
@RequestMapping(UserSignUp.SIGNUP_URL)
|
||||||
|
public class UserSignUp {
|
||||||
|
public static final String SIGNUP_URL = "/signup";
|
||||||
|
|
||||||
|
private final CustomerService customerService;
|
||||||
|
|
||||||
|
public UserSignUp(CustomerService customerService) {
|
||||||
|
this.customerService = customerService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public String showSignupForm(Model model) {
|
||||||
|
model.addAttribute("userDto", new UserSignupDto());
|
||||||
|
return "signup";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public String signup(@ModelAttribute("userDto") @Valid UserSignupDto userSignupDto,
|
||||||
|
BindingResult bindingResult, HttpServletRequest request,
|
||||||
|
Model model) {
|
||||||
|
model.addAttribute("request", request);
|
||||||
|
if (bindingResult.hasErrors()) {
|
||||||
|
model.addAttribute("errors", bindingResult.getAllErrors());
|
||||||
|
return "signup";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final Customer customer = customerService.addCustomer(
|
||||||
|
userSignupDto.getUsername(), userSignupDto.getPassword());
|
||||||
|
return "redirect:/login?created=" + customer.getUsername();
|
||||||
|
} catch (ValidationException e) {
|
||||||
|
model.addAttribute("errors", e.getMessage());
|
||||||
|
return "signup";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,4 +4,5 @@ import np.something.model.Customer;
|
|||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
|
||||||
public interface CustomerRepository extends JpaRepository<Customer, Long> {
|
public interface CustomerRepository extends JpaRepository<Customer, Long> {
|
||||||
|
Customer findByUsername(String username);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
package np.something.security;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class PasswordEncoderConfiguration {
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder createPasswordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
package np.something.security;
|
||||||
|
|
||||||
|
import np.something.model.UserRole;
|
||||||
|
import np.something.mvc.UserSignUp;
|
||||||
|
import np.something.services.CustomerService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
||||||
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
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.WebSecurityConfigurerAdapter;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||||
|
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(SecurityConfiguration.class);
|
||||||
|
private static final String LOGIN_URL = "/login";
|
||||||
|
private final CustomerService customerService;
|
||||||
|
|
||||||
|
public SecurityConfiguration(CustomerService customerService) {
|
||||||
|
this.customerService = customerService;
|
||||||
|
createAdminOnStartup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createAdminOnStartup() {
|
||||||
|
final String admin = "admin";
|
||||||
|
if (customerService.findByUsername(admin) == null) {
|
||||||
|
log.info("Admin user successfully created");
|
||||||
|
customerService.addCustomer(admin, admin, UserRole.ADMIN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http.headers().frameOptions().sameOrigin().and()
|
||||||
|
.cors().and()
|
||||||
|
.csrf().disable()
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers(UserSignUp.SIGNUP_URL).permitAll()
|
||||||
|
.antMatchers(HttpMethod.GET, LOGIN_URL).permitAll()
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
.and()
|
||||||
|
.formLogin()
|
||||||
|
.loginPage(LOGIN_URL).permitAll()
|
||||||
|
.and()
|
||||||
|
.logout().permitAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||||
|
auth.userDetailsService(customerService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(WebSecurity web) {
|
||||||
|
web.ignoring()
|
||||||
|
.antMatchers("/css/**")
|
||||||
|
.antMatchers("/js/**")
|
||||||
|
.antMatchers("/templates/**")
|
||||||
|
.antMatchers("/webjars/**");
|
||||||
|
}
|
||||||
|
}
|
@ -67,7 +67,7 @@ public class CommentService {
|
|||||||
commentRepository.deleteAll();
|
commentRepository.deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@jakarta.transaction.Transactional
|
@Transactional
|
||||||
public List<Comment> searchComments(String tag) {
|
public List<Comment> searchComments(String tag) {
|
||||||
return commentRepository.searchComments(tag);
|
return commentRepository.searchComments(tag);
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,31 @@
|
|||||||
package np.something.services;
|
package np.something.services;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import javax.transaction.Transactional;
|
||||||
import jakarta.persistence.EntityNotFoundException;
|
|
||||||
import jakarta.persistence.PersistenceContext;
|
|
||||||
import jakarta.transaction.Transactional;
|
|
||||||
import np.something.Exceptions.CustomerNotFoundException;
|
import np.something.Exceptions.CustomerNotFoundException;
|
||||||
import np.something.model.Customer;
|
import np.something.model.Customer;
|
||||||
import np.something.repositories.CommentRepository;
|
import np.something.model.UserRole;
|
||||||
import np.something.repositories.CustomerRepository;
|
import np.something.repositories.CustomerRepository;
|
||||||
import np.something.util.validation.ValidatorUtil;
|
import np.something.util.validation.ValidatorUtil;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class CustomerService {
|
public class CustomerService implements UserDetailsService {
|
||||||
private final CustomerRepository customerRepository;
|
private final CustomerRepository customerRepository;
|
||||||
private final ValidatorUtil validatorUtil;
|
private final ValidatorUtil validatorUtil;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
public CustomerService(CustomerRepository customerRepository,
|
public CustomerService(CustomerRepository customerRepository,
|
||||||
ValidatorUtil validatorUtil) {
|
ValidatorUtil validatorUtil, PasswordEncoder passwordEncoder) {
|
||||||
this.customerRepository = customerRepository;
|
this.customerRepository = customerRepository;
|
||||||
this.validatorUtil = validatorUtil;
|
this.validatorUtil = validatorUtil;
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@ -37,7 +40,14 @@ public class CustomerService {
|
|||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public Customer addCustomer(String username, String password) {
|
public Customer addCustomer(String username, String password) {
|
||||||
Customer customer = new Customer(username, password);
|
Customer customer = new Customer(username, passwordEncoder.encode(password));
|
||||||
|
validatorUtil.validate(customer);
|
||||||
|
return customerRepository.save(customer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Customer addCustomer(String username, String password, UserRole role) {
|
||||||
|
Customer customer = new Customer(username, passwordEncoder.encode(password), role);
|
||||||
validatorUtil.validate(customer);
|
validatorUtil.validate(customer);
|
||||||
return customerRepository.save(customer);
|
return customerRepository.save(customer);
|
||||||
}
|
}
|
||||||
@ -46,7 +56,7 @@ public class CustomerService {
|
|||||||
public Customer updateCustomer(Long id, String username, String password) {
|
public Customer updateCustomer(Long id, String username, String password) {
|
||||||
Customer customer = findCustomer(id);
|
Customer customer = findCustomer(id);
|
||||||
customer.setUsername(username);
|
customer.setUsername(username);
|
||||||
customer.setPassword(password);
|
customer.setPassword(passwordEncoder.encode(password));
|
||||||
validatorUtil.validate(customer);
|
validatorUtil.validate(customer);
|
||||||
return customerRepository.save(customer);
|
return customerRepository.save(customer);
|
||||||
}
|
}
|
||||||
@ -62,4 +72,18 @@ public class CustomerService {
|
|||||||
public void deleteAllCustomers() {
|
public void deleteAllCustomers() {
|
||||||
customerRepository.deleteAll();
|
customerRepository.deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Customer findByUsername(String username) {
|
||||||
|
return customerRepository.findByUsername(username);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
|
final Customer customerEntity = findByUsername(username);
|
||||||
|
if (customerEntity == null) {
|
||||||
|
throw new UsernameNotFoundException(username);
|
||||||
|
}
|
||||||
|
return new org.springframework.security.core.userdetails.User(
|
||||||
|
customerEntity.getUsername(), customerEntity.getPassword(), Collections.singleton(customerEntity.getRole()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package np.something.services;
|
package np.something.services;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import jakarta.persistence.EntityNotFoundException;
|
import javax.persistence.EntityNotFoundException;
|
||||||
import jakarta.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
import jakarta.transaction.Transactional;
|
import javax.transaction.Transactional;
|
||||||
import np.something.Exceptions.PostNotFoundException;
|
import np.something.Exceptions.PostNotFoundException;
|
||||||
import np.something.model.Comment;
|
import np.something.model.Comment;
|
||||||
import np.something.model.Customer;
|
import np.something.model.Customer;
|
||||||
|
@ -2,10 +2,10 @@ package np.something.util.validation;
|
|||||||
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import jakarta.validation.ConstraintViolation;
|
import javax.validation.ConstraintViolation;
|
||||||
import jakarta.validation.Validation;
|
import javax.validation.Validation;
|
||||||
import jakarta.validation.Validator;
|
import javax.validation.Validator;
|
||||||
import jakarta.validation.ValidatorFactory;
|
import javax.validation.ValidatorFactory;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -9,3 +9,5 @@ spring.jpa.hibernate.ddl-auto=update
|
|||||||
spring.h2.console.enabled=true
|
spring.h2.console.enabled=true
|
||||||
spring.h2.console.settings.trace=false
|
spring.h2.console.settings.trace=false
|
||||||
spring.h2.console.settings.web-allow-others=false
|
spring.h2.console.settings.web-allow-others=false
|
||||||
|
jwt.dev-token=my-secret-jwt
|
||||||
|
jwt.dev=true
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-3 is-left h3" th:text="${customer.id}"></div>
|
<div class="col-3 is-left h3" th:text="${customer.id}"></div>
|
||||||
<a th:href="${ '/customers/' + customer.id}" class="col-3 is-center h3" th:text="${customer.username}"></a>
|
<a th:href="${ '/customers/' + customer.id}" class="col-3 is-center h3" th:text="${customer.username}"></a>
|
||||||
<div class="col-3 is-right h3" th:text="${customer.password}"></div>
|
<div class="col-3 is-right h3"><span th:text="${customer.password}" style="text-overflow: ellipsis; overflow: hidden; max-width: 10ch; white-space: nowrap"></span></div>
|
||||||
|
|
||||||
<button style="max-width: 66px; max-height: 38px;" th:data-username="${customer.username}" th:data-password="${customer.password}" th:data-id="${customer.id}" th:onclick="|prepareEditModal(this)|" class="button primary outline is-right" data-bs-toggle="modal" data-bs-target="#customerEdit"><i class="fa fa-pencil" aria-hidden="true"></i></button>
|
<button style="max-width: 66px; max-height: 38px;" th:data-username="${customer.username}" th:data-password="${customer.password}" th:data-id="${customer.id}" th:onclick="|prepareEditModal(this)|" class="button primary outline is-right" data-bs-toggle="modal" data-bs-target="#customerEdit"><i class="fa fa-pencil" aria-hidden="true"></i></button>
|
||||||
|
|
||||||
|
@ -9,15 +9,6 @@
|
|||||||
<div class="row mb-5">
|
<div class="row mb-5">
|
||||||
<p class='is-center h2'>Профили</p>
|
<p class='is-center h2'>Профили</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-5">
|
|
||||||
<div class="col"></div>
|
|
||||||
<div class="col-10 is-center">
|
|
||||||
<button class="button primary" data-bs-toggle="modal" data-bs-target="#customerCreate">
|
|
||||||
Добавить нового пользователя
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="col"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p class='h3 is-center row mb-5'>Список профилей</p>
|
<p class='h3 is-center row mb-5'>Список профилей</p>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
@ -25,8 +16,7 @@
|
|||||||
<div th:each="customer: ${customers}" class="row card mb-3">
|
<div th:each="customer: ${customers}" class="row card mb-3">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col is-left h3" th:text="'ID: ' + ${customer.id}"></div>
|
<div class="col is-left h3" th:text="'ID: ' + ${customer.id}"></div>
|
||||||
<div class="col is-center h3" th:text="'Никнейм: ' + ${customer.username}"></div>
|
<div class="col is-right h3" th:text="'Никнейм: ' + ${customer.username}"></div>
|
||||||
<div class="col is-right h3" th:text="'Пароль: ' + ${customer.password}"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<p class="row">Комментарии:</p>
|
<p class="row">Комментарии:</p>
|
||||||
<div class="row" th:unless="${#arrays.isEmpty(customer.comments)}">
|
<div class="row" th:unless="${#arrays.isEmpty(customer.comments)}">
|
||||||
@ -47,7 +37,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p th:if="${#arrays.isEmpty(customer.comments)}" class="row">Нет постов</p>
|
<p th:if="${#arrays.isEmpty(customer.comments)}" class="row">Нет постов</p>
|
||||||
<div class="row" th:if="${session.currentCustomerId == customer.id}">
|
<div class="row" th:if="${currentCustomerId == customer.id}">
|
||||||
<form th:action="@{/customers/delete/{id}(id=${customer.id})}" method="post" class="col">
|
<form th:action="@{/customers/delete/{id}(id=${customer.id})}" method="post" class="col">
|
||||||
<button class="button dark outline is-full-width" type="submit">Удалить</button>
|
<button class="button dark outline is-full-width" type="submit">Удалить</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
<html lang="" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
@ -12,16 +12,15 @@
|
|||||||
<body class="container">
|
<body class="container">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
|
||||||
<div>
|
<div>
|
||||||
<div class="nav row">
|
<div class="nav row" th:with="activeLink=${#request.requestURI}">
|
||||||
<div class="nav-left col-10" th:with="activeLink=${request.requestURI}">
|
<div class="nav-left col-10">
|
||||||
<a href="/customers/" class="button primary" th:classappend="${#strings.startsWith(activeLink, '/customers')} ? 'clear' : ''">Профили</a>
|
<a href="/customers/" class="button primary" th:classappend="${#strings.startsWith(activeLink, '/customers')} ? 'clear' : ''">Профили</a>
|
||||||
<a href="/feed" class="button primary" th:classappend="${#strings.startsWith(activeLink, '/feed')} ? 'clear' : ''">Посты</a>
|
<a href="/feed" class="button primary" th:classappend="${#strings.startsWith(activeLink, '/feed')} ? 'clear' : ''">Посты</a>
|
||||||
|
<a sec:authorize="hasRole('ROLE_ADMIN')" href="/admin/" class="button primary" th:classappend="${#strings.startsWith(activeLink, '/admin')} ? 'clear' : ''">Администрирование</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-right col-2">
|
<div class="nav-right col-2">
|
||||||
<select class="form-select" style="font-size: 16px;" th:onchange="updateSession()" id="selectBox">
|
<a sec:authorize="!isAuthenticated()" href="/login" class="button primary" th:classappend="${#strings.startsWith(activeLink, '/login')} ? 'clear' : ''">Войти</a>
|
||||||
<option value="-1" th:selected="${session.currentCustomerId == -1}" class="button dark outline">Не выбран</option>
|
<a sec:authorize="isAuthenticated()" href="/logout" class="button primary" th:classappend="${#strings.startsWith(activeLink, '/logout')} ? 'clear' : ''">Выйти</a>
|
||||||
<option th:each="customer: ${customers}" th:selected="${session.currentCustomerId == customer.id}" th:value="${customer.id}" class="button dark outline" th:text="${customer.username}"></option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div layout:fragment="content">
|
<div layout:fragment="content">
|
||||||
@ -29,14 +28,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
<script>
|
|
||||||
function updateSession() {
|
|
||||||
let selectBox = document.getElementById("selectBox");
|
|
||||||
let id = selectBox.options[selectBox.selectedIndex].value;
|
|
||||||
fetch("/update-session?currentCustomerId=" + id, {method: "post"})
|
|
||||||
location.reload();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<th:block layout:fragment="scripts">
|
<th:block layout:fragment="scripts">
|
||||||
</th:block>
|
</th:block>
|
||||||
</html>
|
</html>
|
@ -13,10 +13,10 @@
|
|||||||
<input type="search" name="search" class="col-10">
|
<input type="search" name="search" class="col-10">
|
||||||
<button class="button primary col" type="submit">Найти</button>
|
<button class="button primary col" type="submit">Найти</button>
|
||||||
</form>
|
</form>
|
||||||
<div class="row mb-5" th:if="${session.currentCustomerId > 0}">
|
<div class="row mb-5" th:if="${currentCustomerId > 0}">
|
||||||
<div class="col"></div>
|
<div class="col"></div>
|
||||||
<form class="col-10" th:action="@{/posts/}" method="post">
|
<form class="col-10" th:action="@{/posts/}" method="post">
|
||||||
<input name="customerId" type="text" style="display: none;" th:value="${session.currentCustomerId}">
|
<input name="customerId" type="text" style="display: none;" th:value="${currentCustomerId}">
|
||||||
<div class="row mb-4 is-center">
|
<div class="row mb-4 is-center">
|
||||||
<p class="col-2 is-left mb-2">Заголовок:</p>
|
<p class="col-2 is-left mb-2">Заголовок:</p>
|
||||||
<input name="title" type="text" class="col-6" id="createPostTitle" />
|
<input name="title" type="text" class="col-6" id="createPostTitle" />
|
||||||
@ -66,7 +66,7 @@
|
|||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<span class="h3" th:text="${comment.content}"></span>
|
<span class="h3" th:text="${comment.content}"></span>
|
||||||
</div>
|
</div>
|
||||||
<div th:if="${session.currentCustomerId == comment.customerId}" class="row">
|
<div th:if="${currentCustomerId == comment.customerId}" class="row">
|
||||||
<button th:data-content="${comment.content}" th:data-id="${comment.id}" th:onclick="|prepareCommentEditModal(this)|" class="button primary outline col" data-bs-toggle="modal" data-bs-target="#commentEdit">Изменить комментарий</button>
|
<button th:data-content="${comment.content}" th:data-id="${comment.id}" th:onclick="|prepareCommentEditModal(this)|" class="button primary outline col" data-bs-toggle="modal" data-bs-target="#commentEdit">Изменить комментарий</button>
|
||||||
<form th:action="@{/comments/delete/{id}(id=${comment.id})}" method="post" class="col">
|
<form th:action="@{/comments/delete/{id}(id=${comment.id})}" method="post" class="col">
|
||||||
<button type="submit" class="button error is-full-width">Удалить комментарий</button>
|
<button type="submit" class="button error is-full-width">Удалить комментарий</button>
|
||||||
@ -74,7 +74,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p th:if="${#arrays.isEmpty(post.comments)}" class="h3 row is-center mb-5">Пусто</p>
|
<p th:if="${#arrays.isEmpty(post.comments)}" class="h3 row is-center mb-5">Пусто</p>
|
||||||
<form class="row" th:if="${session.currentCustomerId != -1}" th:action="@{/comments/}" method="post">
|
<form class="row" th:if="${currentCustomerId != -1}" th:action="@{/comments/}" method="post">
|
||||||
<input name="content" type="text" class="col-9"/>
|
<input name="content" type="text" class="col-9"/>
|
||||||
<input name="customerId" type="text" style="display: none;" th:value="${session.currentCustomerId}">
|
<input name="customerId" type="text" style="display: none;" th:value="${session.currentCustomerId}">
|
||||||
<input name="postId" type="text" style="display: none;" th:value="${post.id}">
|
<input name="postId" type="text" style="display: none;" th:value="${post.id}">
|
||||||
@ -82,11 +82,11 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row" th:if="${session.currentCustomerId == post.customerId}">
|
<div class="row" th:if="${currentCustomerId == post.customerId}">
|
||||||
<form class="col" th:action="@{/posts/delete/{id}(id=${post.id})}" method="post">
|
<form class="col" th:action="@{/posts/delete/{id}(id=${post.id})}" method="post">
|
||||||
<button type="submit" class="is-full-width button dark outline">Удалить пост</button>
|
<button type="submit" class="is-full-width button dark outline">Удалить пост</button>
|
||||||
</form>
|
</form>
|
||||||
<button th:data-customer="${session.currentCustomerId}" th:data-id="${post.id}" th:data-title="${post.title}" th:data-content="${post.content}" type="button" th:onclick="|preparePostEditModal(this)|" class="col button primary outline" data-bs-toggle="modal" data-bs-target="#postEdit">Изменить пост</button>
|
<button th:data-customer="${currentCustomerId}" th:data-id="${post.id}" th:data-title="${post.title}" th:data-content="${post.content}" type="button" th:onclick="|preparePostEditModal(this)|" class="col button primary outline" data-bs-toggle="modal" data-bs-target="#postEdit">Изменить пост</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
31
src/main/resources/templates/login.html
Normal file
31
src/main/resources/templates/login.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{default}">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div layout:fragment="content">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col"></div>
|
||||||
|
<form class="col-6" action="/login" method="post">
|
||||||
|
<div class="row">
|
||||||
|
<label>Логин: <input type="text" name="username" required /></label>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<label>Пароль: <input type="password" name="password" id="password" required /></label>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-4"></div>
|
||||||
|
<button type="submit" class="button primary col" id="enter">Войти</button>
|
||||||
|
<div class="col-4"></div>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-5">
|
||||||
|
<a class="button primary outline" href="/signup">Регистрация</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="col"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<th:block layout:fragment="scripts">
|
||||||
|
</th:block>
|
||||||
|
</html>
|
44
src/main/resources/templates/signup.html
Normal file
44
src/main/resources/templates/signup.html
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{default}">
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div layout:fragment="content">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col"></div>
|
||||||
|
<form class="col-6" action="/signup" method="post">
|
||||||
|
<div class="row">
|
||||||
|
<label>Логин: <input type="text" name="username" required /></label>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<label>Пароль: <input type="password" name="password" id="password" th:onchange="|check()|" required /></label>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<label>Пароль повторно: <input type="password" id="confirm-password" th:onchange="|check()|" required /></label>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-4"></div>
|
||||||
|
<button type="submit" class="button primary col" id="enter" disabled>Регистрация</button>
|
||||||
|
<div class="col-4"></div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div class="col"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<th:block layout:fragment="scripts">
|
||||||
|
<script th:inline="javascript">
|
||||||
|
function check() {
|
||||||
|
const password = document.getElementById("password")
|
||||||
|
const confpassword = document.getElementById("confirm-password")
|
||||||
|
const button = document.getElementById("enter")
|
||||||
|
|
||||||
|
if (password.value !== confpassword.value) {
|
||||||
|
button.setAttribute('disabled', 'disabled')
|
||||||
|
} else {
|
||||||
|
button.removeAttribute('disabled')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</th:block>
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user