Labwork06 MVC is done.
This commit is contained in:
parent
9d4f79f1ae
commit
475875c357
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -16,6 +16,8 @@ dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-web'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'com.h2database:h2:2.1.214'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-security'
|
||||
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
|
||||
implementation 'junit:junit:4.13.2'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
|
||||
implementation 'org.springframework.boot:spring-boot-devtools'
|
||||
|
BIN
data.mv.db
BIN
data.mv.db
Binary file not shown.
@ -1,52 +0,0 @@
|
||||
package ru.ulstu.is.sbapp.Customer.Controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import ru.ulstu.is.sbapp.Customer.Service.CustomerService;
|
||||
import ru.ulstu.is.sbapp.Movie.Controller.MovieDTO;
|
||||
import ru.ulstu.is.sbapp.WebConfiguration;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(WebConfiguration.REST_API + "/customer")
|
||||
@ControllerAdvice(annotations = RestController.class)
|
||||
public class CustomerController {
|
||||
private final CustomerService customerService;
|
||||
|
||||
public CustomerController(CustomerService customerService)
|
||||
{
|
||||
this.customerService = customerService;
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public CustomerDTO getCustomer(@PathVariable Long id) {
|
||||
return new CustomerDTO(customerService.findCustomer(id));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<CustomerDTO> getCustomers() {
|
||||
return customerService.findAllCustomers().stream().map(CustomerDTO::new).toList();
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public CustomerDTO createCustomer(@RequestParam("fullName") String fullName, @RequestParam("password") String password ) {
|
||||
return new CustomerDTO(customerService.addCustomer(fullName,password));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public CustomerDTO updateCustomer(@PathVariable Long id, @RequestParam("fullName") String fullName) {
|
||||
return new CustomerDTO(customerService.updateCustomer(id,fullName));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public CustomerDTO deleteCustomer(@PathVariable Long id) {
|
||||
return new CustomerDTO(customerService.deleteCustomer(id));
|
||||
}
|
||||
|
||||
@GetMapping("/movies/{customerId}")
|
||||
public List<MovieDTO> getCustomerMovies(@PathVariable("customerId") Long customerId) {
|
||||
return customerService.findCustomerMovies(customerId).stream()
|
||||
.map(MovieDTO::new)
|
||||
.toList();
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package ru.ulstu.is.sbapp.Customer.Controller;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import ru.ulstu.is.sbapp.Customer.Model.Customer;
|
||||
import ru.ulstu.is.sbapp.Customer.Model.CustomerRole;
|
||||
import ru.ulstu.is.sbapp.Movie.Controller.MovieDTO;
|
||||
|
||||
import java.util.List;
|
||||
@ -10,11 +11,13 @@ public class CustomerDTO {
|
||||
private final long id;
|
||||
private final String username;
|
||||
private final String password;
|
||||
private final CustomerRole role;
|
||||
private final List<MovieDTO> movies;
|
||||
public CustomerDTO(Customer customer) {
|
||||
this.id = customer.getId();
|
||||
this.username = customer.getUsername();
|
||||
this.password = customer.getPassword();
|
||||
this.role = customer.getRole();
|
||||
this.movies = customer.getMovies().stream().map(MovieDTO::new).toList();
|
||||
}
|
||||
|
||||
@ -31,6 +34,10 @@ public class CustomerDTO {
|
||||
return password;
|
||||
}
|
||||
|
||||
public CustomerRole getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public List<MovieDTO> getMovies() {
|
||||
return movies;
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
package ru.ulstu.is.sbapp.Customer.Controller;
|
||||
|
||||
import ru.ulstu.is.sbapp.Customer.Model.Customer;
|
||||
import ru.ulstu.is.sbapp.Customer.Model.CustomerRole;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
public class CustomerSignupDTO {
|
||||
|
||||
@NotBlank(message = "Username can't be null or empty")
|
||||
@Size(min = 3, max = 64)
|
||||
private String username;
|
||||
|
||||
@NotBlank(message = "Password can't be empty")
|
||||
@Size(min = 6, max = 64)
|
||||
private String password;
|
||||
private CustomerRole role;
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
public CustomerRole getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRole(CustomerRole role) {
|
||||
this.role = role;
|
||||
}
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
@ -1,14 +1,23 @@
|
||||
package ru.ulstu.is.sbapp.Customer.MVC;
|
||||
|
||||
import org.aspectj.lang.annotation.RequiredTypes;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import ru.ulstu.is.sbapp.Customer.Controller.CustomerDTO;
|
||||
import ru.ulstu.is.sbapp.Customer.Controller.CustomerSignupDTO;
|
||||
import ru.ulstu.is.sbapp.Customer.Model.Customer;
|
||||
import ru.ulstu.is.sbapp.Customer.Service.CustomerService;
|
||||
import ru.ulstu.is.sbapp.Movie.Controller.MovieDTO;
|
||||
import ru.ulstu.is.sbapp.Utilities.CookiesManagement;
|
||||
import ru.ulstu.is.sbapp.Utilities.validation.ValidationException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
@Controller
|
||||
@ -23,22 +32,34 @@ public class CustomerMVC {
|
||||
this.cookiesManagement = new CookiesManagement();
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public String getCustomer(@PathVariable Long id, Model model) {
|
||||
model.addAttribute("customer",new CustomerDTO(customerService.findCustomer(id)));
|
||||
return "customer-details";
|
||||
@GetMapping
|
||||
public String showSignupForm(Model model) {
|
||||
model.addAttribute("customerDTO", new CustomerSignupDTO());
|
||||
return "Registration";
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String getCustomers(Model model) {
|
||||
model.addAttribute("customers", customerService.findAllCustomers().stream().map(CustomerDTO::new).toList());
|
||||
return "Login";
|
||||
@GetMapping("/find/{username}")
|
||||
public Long findCustomer(@PathVariable String username) {
|
||||
return customerService.findByLogin(username).getId();
|
||||
}
|
||||
|
||||
|
||||
@PostMapping
|
||||
public String createCustomer(@RequestParam("fullName") String fullName, @RequestParam("password") String password ) {
|
||||
customerService.addCustomer(fullName,password);
|
||||
return "redirect:/customer";
|
||||
public String createCustomer(@ModelAttribute("customerDTO") @Valid CustomerSignupDTO customerSignupDTO,
|
||||
BindingResult bindingResult,
|
||||
Model model) {
|
||||
if (bindingResult.hasErrors()) {
|
||||
model.addAttribute("errors", bindingResult.getAllErrors());
|
||||
return "Registration";
|
||||
}
|
||||
try {
|
||||
final Customer customer = customerService.createCustomer(
|
||||
customerSignupDTO.getUsername(), customerSignupDTO.getPassword(),customerSignupDTO.getRole());
|
||||
return "redirect:/Login?created=" + customer.getUsername();
|
||||
} catch (ValidationException e) {
|
||||
model.addAttribute("errors", e.getMessage());
|
||||
return "Registration";
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
@ -53,13 +74,22 @@ public class CustomerMVC {
|
||||
}
|
||||
|
||||
@GetMapping("/movies")
|
||||
public String getCustomerMovies(HttpServletRequest request, Model model) {
|
||||
public String getCustomerMovies(Model model) {
|
||||
|
||||
Long userId = Long.parseLong(cookiesManagement.GetUserID(request));
|
||||
model.addAttribute("movies", customerService.findCustomerMovies(userId).stream()
|
||||
String username = null;
|
||||
|
||||
Object principal = SecurityContextHolder. getContext(). getAuthentication(). getPrincipal();
|
||||
if (principal instanceof UserDetails) {
|
||||
username = ((UserDetails)principal). getUsername();
|
||||
} else {
|
||||
username = principal. toString();
|
||||
}
|
||||
|
||||
|
||||
model.addAttribute("movies", customerService.findCustomerMovies(customerService.findByLogin(username).getId()).stream()
|
||||
.map(MovieDTO::new)
|
||||
.toList());
|
||||
model.addAttribute("customerId",userId);
|
||||
model.addAttribute("customerId",customerService.findByLogin(username).getId());
|
||||
return "Librarypage";
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
@Entity
|
||||
public class Customer
|
||||
@ -15,12 +16,16 @@ public class Customer
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private Long id;
|
||||
@Column
|
||||
@Column(nullable = false, unique = true, length = 64)
|
||||
@NotBlank(message = "Username can't be null or empty")
|
||||
@Size(min = 3, max = 64)
|
||||
private String username;
|
||||
@Column
|
||||
@Column(nullable = false, length = 64)
|
||||
@NotBlank(message = "Password can't be empty")
|
||||
@Size(min = 6, max = 64)
|
||||
private String password;
|
||||
|
||||
private CustomerRole role;
|
||||
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||
private List<Movie> movies;
|
||||
|
||||
@ -29,14 +34,15 @@ public class Customer
|
||||
{
|
||||
|
||||
}
|
||||
public Customer(String username,String password)
|
||||
public Customer(String username,String password,CustomerRole role)
|
||||
{
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
|
||||
this.role = role;
|
||||
this.movies = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
public Long getId()
|
||||
{
|
||||
return id;
|
||||
@ -48,6 +54,10 @@ public class Customer
|
||||
return username;
|
||||
}
|
||||
|
||||
public CustomerRole getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setUsername(String username)
|
||||
{
|
||||
this.username = username;
|
||||
|
@ -0,0 +1,20 @@
|
||||
package ru.ulstu.is.sbapp.Customer.Model;
|
||||
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
public enum CustomerRole 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";
|
||||
}
|
||||
}
|
@ -4,4 +4,5 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import ru.ulstu.is.sbapp.Customer.Model.Customer;
|
||||
|
||||
public interface CustomerRepository extends JpaRepository<Customer, Long> {
|
||||
Customer findOneByUsernameIgnoreCase(String login);
|
||||
}
|
||||
|
@ -1,53 +1,67 @@
|
||||
package ru.ulstu.is.sbapp.Customer.Service;
|
||||
|
||||
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.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import ru.ulstu.is.sbapp.Customer.Exception.CustomerNotFoundException;
|
||||
import ru.ulstu.is.sbapp.Customer.Model.Customer;
|
||||
import ru.ulstu.is.sbapp.Customer.Model.CustomerRole;
|
||||
import ru.ulstu.is.sbapp.Customer.Repository.CustomerRepository;
|
||||
import ru.ulstu.is.sbapp.Movie.Model.Movie;
|
||||
import ru.ulstu.is.sbapp.Utilities.validation.ValidationException;
|
||||
import ru.ulstu.is.sbapp.Utilities.validation.ValidatorUtil;
|
||||
import javax.persistence.EntityNotFoundException;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class CustomerService
|
||||
public class CustomerService implements UserDetailsService
|
||||
{
|
||||
private final CustomerRepository customerRepository;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final ValidatorUtil validatorUtil;
|
||||
|
||||
public CustomerService(CustomerRepository customerRepository, ValidatorUtil validatorUtil) {
|
||||
public CustomerService(CustomerRepository customerRepository, ValidatorUtil validatorUtil, PasswordEncoder passwordEncoder) {
|
||||
this.customerRepository = customerRepository;
|
||||
this.validatorUtil = validatorUtil;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Customer addCustomer(String fullName,String password)
|
||||
{
|
||||
if(!StringUtils.hasText(fullName))
|
||||
{
|
||||
throw new IllegalArgumentException("Customer's name or surname is missing");
|
||||
}
|
||||
public Customer findByLogin(String login) {
|
||||
return customerRepository.findOneByUsernameIgnoreCase(login);
|
||||
}
|
||||
|
||||
if(!StringUtils.hasText(password))
|
||||
{
|
||||
throw new IllegalArgumentException("Customer's name or surname is missing");
|
||||
public Customer createCustomer(String login, String password, CustomerRole role){
|
||||
if (findByLogin(login) != null) {
|
||||
throw new ValidationException(String.format("Customer '%s' already exists", login));
|
||||
}
|
||||
|
||||
final Customer customer = new Customer(fullName,password);
|
||||
final Customer customer = new Customer(login,passwordEncoder.encode(password), role);
|
||||
validatorUtil.validate(customer);
|
||||
return customerRepository.save(customer);
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
final Customer customerEntity = findByLogin(username);
|
||||
if (customerEntity == null) {
|
||||
throw new UsernameNotFoundException(username);
|
||||
}
|
||||
return new org.springframework.security.core.userdetails.User(
|
||||
customerEntity.getUsername(), customerEntity.getPassword(), Collections.singleton(customerEntity.getRole()));
|
||||
}
|
||||
|
||||
/*@Transactional(readOnly = true)
|
||||
public Customer findCustomer(Long id)
|
||||
{
|
||||
final Optional<Customer> student = customerRepository.findById(id);
|
||||
return student.orElseThrow(() -> new CustomerNotFoundException(id));
|
||||
}
|
||||
}*/
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<Customer> findAllCustomers()
|
||||
|
@ -48,9 +48,4 @@ public class GenreMVC {
|
||||
return "redirect:/genre";
|
||||
}
|
||||
|
||||
@GetMapping("/fill")
|
||||
public String insertGenres() {
|
||||
genreService.fillRepo();
|
||||
return "redirect:/movies/fill";
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,14 @@
|
||||
package ru.ulstu.is.sbapp.Movie.MVC;
|
||||
|
||||
import org.springframework.security.access.annotation.Secured;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import ru.ulstu.is.sbapp.Customer.Model.CustomerRole;
|
||||
import ru.ulstu.is.sbapp.Customer.Service.CustomerService;
|
||||
import ru.ulstu.is.sbapp.Genre.Controller.GenreDTO;
|
||||
import ru.ulstu.is.sbapp.Genre.Model.Genre;
|
||||
import ru.ulstu.is.sbapp.Genre.Service.GenreService;
|
||||
@ -20,11 +26,13 @@ import java.util.Objects;
|
||||
public class MovieMVC {
|
||||
private final MovieService movieService;
|
||||
private final GenreService genreService;
|
||||
private final CustomerService customerService;
|
||||
private final CookiesManagement cookiesManagement;
|
||||
public MovieMVC(MovieService movieService, GenreService genreService)
|
||||
public MovieMVC(MovieService movieService, GenreService genreService,CustomerService customerService)
|
||||
{
|
||||
this.movieService = movieService;
|
||||
this.genreService = genreService;
|
||||
this.customerService = customerService;
|
||||
this.cookiesManagement = new CookiesManagement();
|
||||
}
|
||||
|
||||
@ -35,16 +43,25 @@ public class MovieMVC {
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public String getMovies(HttpServletRequest request, Model model) {
|
||||
public String getMovies(Model model) {
|
||||
|
||||
genreService.fillRepo();
|
||||
movieService.fillRepo();
|
||||
String username = null;
|
||||
|
||||
Object principal = SecurityContextHolder. getContext(). getAuthentication(). getPrincipal();
|
||||
if (principal instanceof UserDetails) {
|
||||
username = ((UserDetails)principal). getUsername();
|
||||
} else {
|
||||
username = principal. toString();
|
||||
}
|
||||
|
||||
String userId = null;
|
||||
userId = cookiesManagement.GetUserID(request);
|
||||
|
||||
|
||||
model.addAttribute("movies", movieService.findAllMovies().stream()
|
||||
.map(MovieDTO::new)
|
||||
.toList());
|
||||
model.addAttribute("userId", userId);
|
||||
model.addAttribute("userId", customerService.findByLogin(username).getId());
|
||||
return "Mainpage";
|
||||
}
|
||||
|
||||
@ -85,29 +102,43 @@ public class MovieMVC {
|
||||
}
|
||||
|
||||
@PostMapping("/movie/delete/{id}")
|
||||
@Secured({CustomerRole.AsString.ADMIN})
|
||||
public String deleteMovie(@PathVariable("id") Long id) {
|
||||
movieService.deleteMovie(id);
|
||||
return "redirect:/movie";
|
||||
return "redirect:/movies";
|
||||
}
|
||||
|
||||
@PostMapping("/customer/{id}")
|
||||
public String assignMovie(HttpServletRequest request,@PathVariable("id") Long id) {
|
||||
public String assignMovie(@PathVariable("id") Long id) {
|
||||
|
||||
Long customerId = Long.parseLong(cookiesManagement.GetUserID(request));
|
||||
movieService.assignMovie(customerId, id);
|
||||
String username = null;
|
||||
|
||||
Object principal = SecurityContextHolder. getContext(). getAuthentication(). getPrincipal();
|
||||
if (principal instanceof UserDetails) {
|
||||
username = ((UserDetails)principal). getUsername();
|
||||
} else {
|
||||
username = principal. toString();
|
||||
}
|
||||
|
||||
|
||||
movieService.assignMovie(customerService.findByLogin(username).getId(), id);
|
||||
return "redirect:/movies";
|
||||
}
|
||||
|
||||
@PostMapping("/customer/delete/{id}")
|
||||
public String deleteMovieCustomer(HttpServletRequest request, @PathVariable("id") Long id) {
|
||||
Long customerId = Long.parseLong(cookiesManagement.GetUserID(request));
|
||||
movieService.deleteMovieCustomer(id, customerId);
|
||||
public String deleteMovieCustomer(@PathVariable("id") Long id) {
|
||||
|
||||
String username = null;
|
||||
|
||||
Object principal = SecurityContextHolder. getContext(). getAuthentication(). getPrincipal();
|
||||
if (principal instanceof UserDetails) {
|
||||
username = ((UserDetails)principal). getUsername();
|
||||
} else {
|
||||
username = principal. toString();
|
||||
}
|
||||
|
||||
movieService.deleteMovieCustomer(id, customerService.findByLogin(username).getId());
|
||||
return "redirect:/customer/movies";
|
||||
}
|
||||
|
||||
@GetMapping("/fill")
|
||||
public String insertMovies() {
|
||||
movieService.fillRepo();
|
||||
return "redirect:/movies";
|
||||
}
|
||||
}
|
||||
|
@ -162,12 +162,15 @@ public class MovieService
|
||||
|
||||
specificMovie.getGenre().getMovies().remove(specificMovie);
|
||||
|
||||
movieRepository.delete(specificMovie);
|
||||
final List<Customer> customers = customerRepository.findAll();
|
||||
|
||||
customers.forEach(customer -> {
|
||||
customer.getMovies().remove(specificMovie);
|
||||
});
|
||||
|
||||
movieRepository.delete(specificMovie);
|
||||
|
||||
return specificMovie;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,14 @@
|
||||
package ru.ulstu.is.sbapp;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
53
src/main/java/ru/ulstu/is/sbapp/SecurityConfiguration.java
Normal file
53
src/main/java/ru/ulstu/is/sbapp/SecurityConfiguration.java
Normal file
@ -0,0 +1,53 @@
|
||||
package ru.ulstu.is.sbapp;
|
||||
|
||||
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;
|
||||
import ru.ulstu.is.sbapp.Customer.Service.CustomerService;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true)
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
private static final String LOGIN_URL = "/Login";
|
||||
private static final String SIGNUP_URL = "/customer";
|
||||
private final CustomerService customerService;
|
||||
|
||||
public SecurityConfiguration(CustomerService customerService) {
|
||||
this.customerService = customerService;
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.headers().frameOptions().sameOrigin().and()
|
||||
.cors().and()
|
||||
.csrf().disable()
|
||||
.authorizeRequests()
|
||||
.antMatchers(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/**");
|
||||
}
|
||||
}
|
@ -6,4 +6,7 @@ public class ValidationException extends RuntimeException {
|
||||
public ValidationException(Set<String> errors) {
|
||||
super(String.join("\n", errors));
|
||||
}
|
||||
public <T> ValidationException(String error) {
|
||||
super(error);
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,18 @@ package ru.ulstu.is.sbapp;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class WebConfiguration implements WebMvcConfigurer {
|
||||
public static final String REST_API = "/api";
|
||||
@Override
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
WebMvcConfigurer.super.addViewControllers(registry);
|
||||
registry.addViewController("Login");
|
||||
}
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**").allowedMethods("*");
|
||||
}
|
||||
|
@ -4,28 +4,38 @@
|
||||
</head>
|
||||
|
||||
<div layout:fragment="content">
|
||||
<div th:if="${param.error}" class="alert alert-danger margin-bottom">
|
||||
User isn't found or password isn't correct
|
||||
</div>
|
||||
<div th:if="${param.logout}" class="alert alert-success margin-bottom">
|
||||
Successful logout
|
||||
</div>
|
||||
<div th:if="${param.created}" class="alert alert-success margin-bottom">
|
||||
User '<span th:text="${param.created}"></span>' was successfully created
|
||||
</div>
|
||||
<div class="flex-container" style="flex-direction: column; display: flex; ">
|
||||
<div class="flex-container min-vh-100" style="flex-direction: column; display: flex; align-items: center; justify-content: center; gap: 20px;">
|
||||
<h1 for="userSelect" style="color: white;">Select User:</h1>
|
||||
<select id="userSelect" style="width: 100px;">
|
||||
<option th:each="customer : ${customers}" th:value="${customer.getID()}" th:text="${customer.username}"></option>
|
||||
</select>
|
||||
<button style="margin-top: 50px;" onclick="handleLogin()">Login</button>
|
||||
<form th:action="@{/Login}" method="post" class="container-padding">
|
||||
<div class="mb-3">
|
||||
<input type="text" name="username" id="username" class="form-control"
|
||||
placeholder="Login" required="true" autofocus="true"/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<input type="password" name="password" id="password" class="form-control"
|
||||
placeholder="Password" required="true"/>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success button-fixed" >Login</button>
|
||||
<a class="btn btn-primary button-fixed" href="/customer">Registration</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<th:block layout:fragment="scripts">
|
||||
<script>
|
||||
|
||||
|
||||
|
||||
|
||||
function handleLogin() {
|
||||
localStorage.clear();
|
||||
var selectedUserId = document.getElementById("userSelect").value;
|
||||
document.cookie = "userID=" + selectedUserId;
|
||||
window.location.href = "/genre/fill";
|
||||
}
|
||||
</script>
|
||||
</th:block>
|
||||
</html>
|
@ -5,22 +5,25 @@
|
||||
|
||||
<div layout:fragment="content">
|
||||
|
||||
|
||||
|
||||
<div class="flex-container min-vh-100" style="flex-direction: row; display: flex; margin-left: 20px; margin-top: 50px;">
|
||||
<div th:if="${not #lists.isEmpty(movies)}" style="flex-direction: row; display: flex; flex-wrap: wrap; justify-content: space-between;">
|
||||
<div th:each="movie : ${movies}" style="margin-bottom: 20px;">
|
||||
<div className="flex-containerB" style="flex-direction: column; display: flex; width: 250px; height: 350px; gap:40px; align-items:center;">
|
||||
<img src="https://www.seekpng.com/png/detail/8-84931_question-mark-question-mark-white-background.png" alt = "cover" width="100%" height="300px"/>
|
||||
<h3><a th:href="@{/movies/movie/{movieId}(movieId=${movie.getID()})}"
|
||||
th:text="${movie.title}" style="text-decoration: none; color: white;"></a></h3>
|
||||
<button type="button" th:attr="data-movie-id=${movie.getID()}" onclick="handleAcquireMovie(event)">Acquire</button>
|
||||
|
||||
<div th:if="${not #lists.isEmpty(movies)}" style="flex-direction: row; display: flex; flex-wrap: wrap; justify-content: space-between;">
|
||||
<div th:each="movie : ${movies}" style="margin-bottom: 20px;">
|
||||
<div className="flex-containerB" style="flex-direction: column; display: flex; width: 250px; height: 350px; gap:40px; align-items:center;">
|
||||
<img src="https://www.seekpng.com/png/detail/8-84931_question-mark-question-mark-white-background.png" alt = "cover" width="100%" height="300px"/>
|
||||
<h3><a th:href="@{/movies/movie/{movieId}(movieId=${movie.getID()})}"
|
||||
th:text="${movie.title}" style="text-decoration: none; color: white;"></a></h3>
|
||||
<button type="btn btn-primary" th:attr="data-movie-id=${movie.getID()}" onclick="handleAcquireMovie(event)">Acquire</button>
|
||||
<button type="btn btn-primary" th:attr="data-movie-id=${movie.getID()}" onclick="handleDeleteMovie(event)">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h1 th:unless="${not #lists.isEmpty(movies)}" style="color: white;">No movies available</h1>
|
||||
<h1 th:unless="${not #lists.isEmpty(movies)}" style="color: white;">No movies available</h1>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<th:block layout:fragment="scripts">
|
||||
@ -34,6 +37,16 @@
|
||||
}) ;
|
||||
}
|
||||
|
||||
function handleDeleteMovie(movieId){
|
||||
var movieId = event.target.getAttribute("data-movie-id");
|
||||
var url = "/movies/movie/delete/" + movieId;
|
||||
fetch(url,{
|
||||
method: "POST",
|
||||
}) ;
|
||||
window.location.href = "/movies"
|
||||
location.reload();
|
||||
}
|
||||
|
||||
</script>
|
||||
</th:block>
|
||||
</html>
|
44
src/main/resources/templates/Registration.html
Normal file
44
src/main/resources/templates/Registration.html
Normal file
@ -0,0 +1,44 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" layout:decorate="~{Template}">
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<div layout:fragment="content">
|
||||
<div th:if="${errors}" th:text="${errors}" class="margin-bottom alert alert-danger"></div>
|
||||
<div class="flex-container" style="flex-direction: column; display: flex;">
|
||||
<div class="flex-container min-vh-100" style="flex-direction: column; display: flex;">
|
||||
<main style="display: flex; flex: 1;">
|
||||
<aside class="flex-item2" style="flex: 2;"></aside>
|
||||
<div class="flex-item3 align-self-center" style="flex: 3;"><img src="https://i.pinimg.com/736x/57/ee/6a/57ee6a23a455b12eff3aa13d63f104cd.jpg" alt="cover" width="100%" height="600px"/></div>
|
||||
<section class="flex-container align-self-center" style="height: 660px; flex: 4; background-color: #ffd79d; flex-direction: column; display: flex;">
|
||||
<form action="#" th:action="@{/customer}" th:object="${customerDTO}" method="post">
|
||||
<section class="flex-itemR1" style="color: #320D3E; font-size: 50px; font-weight: bold; padding-left: 30px; padding-top: 10px;">SIGN UP</section>
|
||||
<section class="flex-itemR2" style="color: #320D3E; font-size: 35px; font-weight: bold; padding-left: 30px; padding-top: 10px;">
|
||||
<label style="color: #320D3E; font-size: 32px; font-weight: bold;">USERNAME</label>
|
||||
</section>
|
||||
<section class="flex-itemR3" style="display: flex; width: 320px; padding-left: 30px;">
|
||||
<input class="form-control" id="inputUsername" type="string" name="username" placeholder="Enter username" th:field="${customerDTO.username}" required="true" autofocus="true" maxlength="64"/>
|
||||
</section>
|
||||
<section class="flex-itemR6" style="color: #320D3E; font-size: 35px; font-weight: bold; padding-left: 30px; padding-top: 10px;">
|
||||
<label style="color: #320D3E; font-size: 32px; font-weight: bold;">PASSWORD</label>
|
||||
</section>
|
||||
<section class="flex-itemR7" style="display: flex; width: 320px; padding-left: 30px;">
|
||||
<input class="form-control" id="inputPassword" type="password" name="password" placeholder="Enter password" th:field="${customerDTO.password}" required="true" minlength="6" maxlength="64"/>
|
||||
</section>
|
||||
<section class="flex-itemR8" style="display: flex; width: 320px; padding-left: 30px;">
|
||||
<select id="genre-select" th:field="${customerDTO.role}" required="true">
|
||||
<option value="USER">USER</option>
|
||||
<option value="ADMIN">ADMIN</option>
|
||||
</select>
|
||||
</section>
|
||||
<button class="btn btn-primary" type="submit" id="register" style="font-size: 20px; margin-left: 30px; margin-top: 15px; width: 150px; background-color: #320D3E; color: white; font-weight: bold;">Register</button>
|
||||
<a href="/Login">Sign in</a>
|
||||
</form>
|
||||
</section>
|
||||
<aside class="flex-item5" style="flex: 2;"></aside>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</html>
|
@ -1,7 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en"
|
||||
xmlns:th="http://www.thymeleaf.org"
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
|
||||
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
||||
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<title>I'M TIRED OF IP</title>
|
||||
@ -12,7 +13,7 @@
|
||||
|
||||
<div style="background-image: url('https://img.freepik.com/premium-vector/grainy-gradient-background-using-different-colors_606954-9.jpg');">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<ul class="navbar-nav mr-auto" sec:authorize="isAuthenticated()">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="/movies" th:classappend="${#strings.equals(activeLink, '/movies')} ? 'active' : ''">
|
||||
Main Page
|
||||
@ -29,7 +30,7 @@
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="/" th:classappend="${#strings.equals(activeLink, '/')} ? 'active' : ''">
|
||||
<a class="nav-link" href="/customer" th:classappend="${#strings.equals(activeLink, '/')} ? 'active' : ''">
|
||||
Registration Page
|
||||
</a>
|
||||
</li>
|
||||
|
@ -4,34 +4,16 @@
|
||||
</head>
|
||||
|
||||
<div layout:fragment="content">
|
||||
<div class="flex-container" style="flex-direction: column; display: flex;">
|
||||
<div class="flex-container min-vh-100" style="flex-direction: column; display: flex;">
|
||||
<main style="display: flex; flex: 1;">
|
||||
<aside class="flex-item2" style="flex: 2;"></aside>
|
||||
<div class="flex-item3 align-self-center" style="flex: 3;"><img src="https://i.pinimg.com/736x/57/ee/6a/57ee6a23a455b12eff3aa13d63f104cd.jpg" alt="cover" width="100%" height="600px"/></div>
|
||||
<section class="flex-container align-self-center" style="height: 660px; flex: 4; background-color: #ffd79d; flex-direction: column; display: flex;">
|
||||
<form action="#" th:action="@{/customer}" method="post">
|
||||
<section class="flex-itemR1" style="color: #320D3E; font-size: 50px; font-weight: bold; padding-left: 30px; padding-top: 10px;">SIGN UP</section>
|
||||
<section class="flex-itemR2" style="color: #320D3E; font-size: 35px; font-weight: bold; padding-left: 30px; padding-top: 10px;">
|
||||
<label style="color: #320D3E; font-size: 32px; font-weight: bold;">USERNAME</label>
|
||||
</section>
|
||||
<section class="flex-itemR3" style="display: flex; width: 320px; padding-left: 30px;">
|
||||
<input class="form-control" id="inputUsername" type="string" name="fullName" placeholder="Enter username" th:value="${inputUsername}"/>
|
||||
</section>
|
||||
<section class="flex-itemR6" style="color: #320D3E; font-size: 35px; font-weight: bold; padding-left: 30px; padding-top: 10px;">
|
||||
<label style="color: #320D3E; font-size: 32px; font-weight: bold;">PASSWORD</label>
|
||||
</section>
|
||||
<section class="flex-itemR7" style="display: flex; width: 320px; padding-left: 30px;">
|
||||
<input class="form-control" id="inputPassword" type="password" name="password" placeholder="Enter password" th:value="${inputPassword}"/>
|
||||
</section>
|
||||
<button class="btn btn-primary" type="submit" id="register" style="font-size: 20px; margin-left: 30px; margin-top: 15px; width: 150px; background-color: #320D3E; color: white; font-weight: bold;">Register</button>
|
||||
<a href="/customer">Sign in</a>
|
||||
</form>
|
||||
</section>
|
||||
<aside class="flex-item5" style="flex: 2;"></aside>
|
||||
</main>
|
||||
|
||||
|
||||
<div class="flex-container min-vh-100" style="flex-direction: row; display: flex; margin-left: 20px; margin-top: 50px;">
|
||||
|
||||
|
||||
<h1 style="color: white;">THE BEST ONLINE-CINEMA</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user