diff --git a/build.gradle b/build.gradle index b2eff23..36cc235 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,9 @@ dependencies { implementation 'org.hibernate.validator:hibernate-validator' + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5' + implementation 'org.springdoc:springdoc-openapi-ui:1.6.5' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/data.mv.db b/data.mv.db index b42c008..3abbc24 100644 Binary files a/data.mv.db and b/data.mv.db differ diff --git a/src/main/java/ru/ulstu/is/sbapp/configuration/PasswordEncoderConfiguration.java b/src/main/java/ru/ulstu/is/sbapp/configuration/PasswordEncoderConfiguration.java new file mode 100644 index 0000000..fadfa18 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/configuration/PasswordEncoderConfiguration.java @@ -0,0 +1,14 @@ +package ru.ulstu.is.sbapp.configuration; + +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(); + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/configuration/SecurityConfiguration.java b/src/main/java/ru/ulstu/is/sbapp/configuration/SecurityConfiguration.java new file mode 100644 index 0000000..3851f07 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/configuration/SecurityConfiguration.java @@ -0,0 +1,68 @@ +package ru.ulstu.is.sbapp.configuration; + +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; +import ru.ulstu.is.sbapp.socialNetwork.controller.UserSignupMvcController; +import ru.ulstu.is.sbapp.socialNetwork.models.UserRole; +import ru.ulstu.is.sbapp.socialNetwork.services.MyUserService; +import ru.ulstu.is.sbapp.socialNetwork.services.UserService; + +@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 UserService userService; + + public SecurityConfiguration(UserService userService) { + this.userService = userService; + createAdminOnStartup(); + } + + private void createAdminOnStartup() { + final String admin = "admin"; + if (userService.findByLogin(admin) == null) { + log.info("Admin user successfully created"); + userService.createUser(admin, admin, admin, UserRole.ADMIN); + } + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http.headers().frameOptions().sameOrigin().and() + .cors().and() + .csrf().disable() + .authorizeRequests() + .antMatchers(UserSignupMvcController.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(userService); + } + + @Override + public void configure(WebSecurity web) { + web.ignoring() + .antMatchers("/css/**") + .antMatchers("/js/**") + .antMatchers("/templates/**") + .antMatchers("/webjars/**"); + } +} \ No newline at end of file diff --git a/src/main/java/ru/ulstu/is/sbapp/WebConfiguration.java b/src/main/java/ru/ulstu/is/sbapp/configuration/WebConfiguration.java similarity index 92% rename from src/main/java/ru/ulstu/is/sbapp/WebConfiguration.java rename to src/main/java/ru/ulstu/is/sbapp/configuration/WebConfiguration.java index 1155aa3..91f2516 100644 --- a/src/main/java/ru/ulstu/is/sbapp/WebConfiguration.java +++ b/src/main/java/ru/ulstu/is/sbapp/configuration/WebConfiguration.java @@ -1,4 +1,4 @@ -package ru.ulstu.is.sbapp; +package ru.ulstu.is.sbapp.configuration; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; @@ -20,6 +20,7 @@ public class WebConfiguration implements WebMvcConfigurer { registry.addViewController("users"); registry.addViewController("contacts"); registry.addViewController("catalogs"); + registry.addViewController("login"); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/CommunityController.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/CommunityController.java index 38dee1a..5b26f1f 100644 --- a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/CommunityController.java +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/CommunityController.java @@ -1,7 +1,7 @@ package ru.ulstu.is.sbapp.socialNetwork.controller; import org.springframework.web.bind.annotation.*; -import ru.ulstu.is.sbapp.WebConfiguration; +import ru.ulstu.is.sbapp.configuration.WebConfiguration; import ru.ulstu.is.sbapp.socialNetwork.dto.CommunityDTO; import ru.ulstu.is.sbapp.socialNetwork.services.CommunityService; diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/MusicController.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/MusicController.java index 21e68dc..5b19dab 100644 --- a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/MusicController.java +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/MusicController.java @@ -2,11 +2,9 @@ package ru.ulstu.is.sbapp.socialNetwork.controller; import org.springframework.web.bind.annotation.*; -import ru.ulstu.is.sbapp.WebConfiguration; +import ru.ulstu.is.sbapp.configuration.WebConfiguration; import ru.ulstu.is.sbapp.socialNetwork.dto.MusicDTO; -import ru.ulstu.is.sbapp.socialNetwork.models.Music; import ru.ulstu.is.sbapp.socialNetwork.services.MusicService; -import org.springframework.web.bind.annotation.*; import javax.validation.Valid; import java.util.List; diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/UserController.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/UserController.java index a56a3fb..7f422c0 100644 --- a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/UserController.java +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/UserController.java @@ -1,10 +1,10 @@ package ru.ulstu.is.sbapp.socialNetwork.controller; import org.springframework.web.bind.annotation.*; -import ru.ulstu.is.sbapp.WebConfiguration; -import ru.ulstu.is.sbapp.socialNetwork.dto.UserDTO; +import ru.ulstu.is.sbapp.configuration.WebConfiguration; +import ru.ulstu.is.sbapp.socialNetwork.dto.MyUserDTO; import ru.ulstu.is.sbapp.socialNetwork.models.UserModel; -import ru.ulstu.is.sbapp.socialNetwork.services.UserService; +import ru.ulstu.is.sbapp.socialNetwork.services.MyUserService; import javax.validation.Valid; @@ -14,55 +14,55 @@ import java.util.List; @RestController @RequestMapping(WebConfiguration.REST_API + "/users") public class UserController { - private final UserService userService; + private final MyUserService userService; - public UserController(UserService userService){ + public UserController(MyUserService userService){ this.userService = userService; } @GetMapping("/{id}") - public UserDTO getUser(@PathVariable Long id) { - return new UserDTO(userService.findUser(id)); + public MyUserDTO getUser(@PathVariable Long id) { + return new MyUserDTO(userService.findUser(id)); } @GetMapping("") - public List getUsers() { - return userService.findAllUsers().stream().map(UserDTO::new).toList(); + public List getUsers() { + return userService.findAllUsers().stream().map(MyUserDTO::new).toList(); } @PostMapping("") - public UserDTO createUser(@RequestBody @Valid UserDTO user) { + public MyUserDTO createUser(@RequestBody @Valid MyUserDTO user) { UserModel result = userService.addUser(user.getName(), user.getCity()); userService.updateCommunities(result.getId(), user.getCommunity()); - return new UserDTO(userService.updateMusics(result.getId(), user.getMusic())); + return new MyUserDTO(userService.updateMusics(result.getId(), user.getMusic())); } @PatchMapping("/{id}") - public UserDTO updateUser(@PathVariable Long id, - @RequestBody @Valid UserDTO user) { + public MyUserDTO updateUser(@PathVariable Long id, + @RequestBody @Valid MyUserDTO user) { UserModel result = userService.updateUser(id, user.getName()); userService.updateCommunities(result.getId(), user.getCommunity()); - return new UserDTO(userService.updateMusics(result.getId(), user.getMusic())); + return new MyUserDTO(userService.updateMusics(result.getId(), user.getMusic())); } @PatchMapping("/add_music/{id}") - public UserDTO addMusic(@PathVariable Long id, @RequestParam Long music_id) { - return new UserDTO(userService.addMusic(id, music_id)); + public MyUserDTO addMusic(@PathVariable Long id, @RequestParam Long music_id) { + return new MyUserDTO(userService.addMusic(id, music_id)); } @PatchMapping("/add_community/{id}") - public UserDTO addCommunity(@PathVariable Long id, @RequestParam Long community_id) { - return new UserDTO(userService.addCommunity(id, community_id)); + public MyUserDTO addCommunity(@PathVariable Long id, @RequestParam Long community_id) { + return new MyUserDTO(userService.addCommunity(id, community_id)); } @GetMapping("/search") - public List searchUsers(@RequestParam("city") String city) { + public List searchUsers(@RequestParam("city") String city) { List users = userService.findUserByCity(city); - return users.stream().map(UserDTO::new).toList(); + return users.stream().map(MyUserDTO::new).toList(); } @DeleteMapping("/{id}") - public UserDTO deleteUser(@PathVariable Long id) { - return new UserDTO(userService.deleteUser(id)); + public MyUserDTO deleteUser(@PathVariable Long id) { + return new MyUserDTO(userService.deleteUser(id)); } } diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/UserMvcController.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/UserMvcController.java new file mode 100644 index 0000000..54a600b --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/UserMvcController.java @@ -0,0 +1,42 @@ +package ru.ulstu.is.sbapp.socialNetwork.controller; + +import org.springframework.data.domain.Page; +import org.springframework.security.access.annotation.Secured; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import ru.ulstu.is.sbapp.socialNetwork.dto.UserDto; +import ru.ulstu.is.sbapp.socialNetwork.models.UserRole; +import ru.ulstu.is.sbapp.socialNetwork.services.UserService; + +import java.util.List; +import java.util.stream.IntStream; + +@Controller +@RequestMapping("/users") +public class UserMvcController { + private final UserService userService; + + public UserMvcController(UserService userService) { + this.userService = userService; + } + + @GetMapping + @Secured({UserRole.AsString.ADMIN}) + public String getUsers(@RequestParam(defaultValue = "1") int page, + @RequestParam(defaultValue = "5") int size, + Model model) { + final Page users = userService.findAllPages(page, size) + .map(UserDto::new); + model.addAttribute("users", users); + final int totalPages = users.getTotalPages(); + final List pageNumbers = IntStream.rangeClosed(1, totalPages) + .boxed() + .toList(); + model.addAttribute("pages", pageNumbers); + model.addAttribute("totalPages", totalPages); + return "users"; + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/UserSignupMvcController.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/UserSignupMvcController.java new file mode 100644 index 0000000..fa47a25 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/controller/UserSignupMvcController.java @@ -0,0 +1,51 @@ +package ru.ulstu.is.sbapp.socialNetwork.controller; + +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 ru.ulstu.is.sbapp.socialNetwork.models.User; +import ru.ulstu.is.sbapp.socialNetwork.models.UserSignupDto; +import ru.ulstu.is.sbapp.socialNetwork.services.UserService; +import ru.ulstu.is.sbapp.socialNetwork.util.validation.ValidationException; + +import javax.validation.Valid; + +@Controller +@RequestMapping(UserSignupMvcController.SIGNUP_URL) +public class UserSignupMvcController { + public static final String SIGNUP_URL = "/signup"; + + private final UserService userService; + + public UserSignupMvcController(UserService userService) { + this.userService = userService; + } + + @GetMapping + public String showSignupForm(Model model) { + model.addAttribute("userDto", new UserSignupDto()); + return "signup"; + } + + @PostMapping + public String signup(@ModelAttribute("userDto") @Valid UserSignupDto userSignupDto, + BindingResult bindingResult, + Model model) { + if (bindingResult.hasErrors()) { + model.addAttribute("errors", bindingResult.getAllErrors()); + return "signup"; + } + try { + final User user = userService.createUser( + userSignupDto.getLogin(), userSignupDto.getPassword(), userSignupDto.getPasswordConfirm()); + return "redirect:/login?created=" + user.getLogin(); + } catch (ValidationException e) { + model.addAttribute("errors", e.getMessage()); + return "signup"; + } + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/dto/UserDTO.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/dto/MyUserDTO.java similarity index 93% rename from src/main/java/ru/ulstu/is/sbapp/socialNetwork/dto/UserDTO.java rename to src/main/java/ru/ulstu/is/sbapp/socialNetwork/dto/MyUserDTO.java index 001a166..80d1f17 100644 --- a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/dto/UserDTO.java +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/dto/MyUserDTO.java @@ -6,14 +6,14 @@ import ru.ulstu.is.sbapp.socialNetwork.models.UserModel; import java.util.List; -public class UserDTO { +public class MyUserDTO { private Long id; private String name; private String city; - public UserDTO(){} + public MyUserDTO(){} - public UserDTO(UserModel user){ + public MyUserDTO(UserModel user){ this.id = user.getId(); this.name = user.getName(); @@ -25,7 +25,7 @@ public class UserDTO { this.community = user.getGroups().stream().map(Community::getName).toList(); } } - public UserDTO(Long id, String name) { + public MyUserDTO(Long id, String name) { this.id = id; this.name = name; } diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/dto/UserDto.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/dto/UserDto.java new file mode 100644 index 0000000..6bfc837 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/dto/UserDto.java @@ -0,0 +1,28 @@ +package ru.ulstu.is.sbapp.socialNetwork.dto; + +import ru.ulstu.is.sbapp.socialNetwork.models.User; +import ru.ulstu.is.sbapp.socialNetwork.models.UserRole; + +public class UserDto { + private final long id; + private final String login; + private final UserRole role; + + public UserDto(User user) { + this.id = user.getId(); + this.login = user.getLogin(); + this.role = user.getRole(); + } + + public long getId() { + return id; + } + + public String getLogin() { + return login; + } + + public UserRole getRole() { + return role; + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/models/User.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/models/User.java new file mode 100644 index 0000000..eb68c19 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/models/User.java @@ -0,0 +1,73 @@ +package ru.ulstu.is.sbapp.socialNetwork.models; + +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; +import java.util.Objects; + +@Entity +@Table(name = "users") +public class User { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + private Long id; + @Column(nullable = false, unique = true, length = 64) + @NotBlank + @Size(min = 3, max = 64) + private String login; + @Column(nullable = false, length = 64) + @NotBlank + @Size(min = 6, max = 64) + private String password; + private UserRole role; + + public User() { + } + + public User(String login, String password) { + this(login, password, UserRole.USER); + } + + public User(String login, String password, UserRole role) { + this.login = login; + this.password = password; + this.role = role; + } + + public Long getId() { + return id; + } + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public UserRole getRole() { + return role; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + User user = (User) o; + return Objects.equals(id, user.id) && Objects.equals(login, user.login); + } + + @Override + public int hashCode() { + return Objects.hash(id, login); + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/models/UserRole.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/models/UserRole.java new file mode 100644 index 0000000..712e742 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/models/UserRole.java @@ -0,0 +1,20 @@ +package ru.ulstu.is.sbapp.socialNetwork.models; + +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"; + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/models/UserSignupDto.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/models/UserSignupDto.java new file mode 100644 index 0000000..0745e89 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/models/UserSignupDto.java @@ -0,0 +1,40 @@ +package ru.ulstu.is.sbapp.socialNetwork.models; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Size; + +public class UserSignupDto { + @NotBlank + @Size(min = 3, max = 64) + private String login; + @NotBlank + @Size(min = 6, max = 64) + private String password; + @NotBlank + @Size(min = 6, max = 64) + private String passwordConfirm; + + public String getLogin() { + return login; + } + + public void setLogin(String login) { + this.login = login; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getPasswordConfirm() { + return passwordConfirm; + } + + public void setPasswordConfirm(String passwordConfirm) { + this.passwordConfirm = passwordConfirm; + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/repository/MyUserRepository.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/repository/MyUserRepository.java new file mode 100644 index 0000000..2c2db01 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/repository/MyUserRepository.java @@ -0,0 +1,10 @@ +package ru.ulstu.is.sbapp.socialNetwork.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ru.ulstu.is.sbapp.socialNetwork.models.UserModel; + +import java.util.List; + +public interface MyUserRepository extends JpaRepository { + List findByCity(String city); +} diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/repository/UserRepository.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/repository/UserRepository.java index af1876a..a082d66 100644 --- a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/repository/UserRepository.java +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/repository/UserRepository.java @@ -1,10 +1,8 @@ package ru.ulstu.is.sbapp.socialNetwork.repository; import org.springframework.data.jpa.repository.JpaRepository; -import ru.ulstu.is.sbapp.socialNetwork.models.UserModel; +import ru.ulstu.is.sbapp.socialNetwork.models.User; -import java.util.List; - -public interface UserRepository extends JpaRepository { - List findByCity(String city); +public interface UserRepository extends JpaRepository { + User findOneByLoginIgnoreCase(String login); } diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/services/MyUserService.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/services/MyUserService.java new file mode 100644 index 0000000..467283b --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/services/MyUserService.java @@ -0,0 +1,211 @@ +package ru.ulstu.is.sbapp.socialNetwork.services; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import ru.ulstu.is.sbapp.socialNetwork.models.Community; +import ru.ulstu.is.sbapp.socialNetwork.models.Music; +import ru.ulstu.is.sbapp.socialNetwork.models.UserModel; +import ru.ulstu.is.sbapp.socialNetwork.repository.MyUserRepository; + +import javax.persistence.EntityNotFoundException; +import java.util.List; +import java.util.Optional; + +@Service +public class MyUserService { + + private MyUserRepository repo; + + private CommunityService communityService; + private MusicService musicService; + + public MyUserService(MyUserRepository repo, MusicService musicService, CommunityService communityService) { + this.repo = repo; + this.musicService = musicService; + this.communityService = communityService; + } + + @Transactional + public UserModel addUser(String name, String city) { + if (!StringUtils.hasText(name)) { + throw new IllegalArgumentException("User name is null or empty"); + } + UserModel user = new UserModel(name, city); + return repo.save(user); + } + @Transactional + public UserModel addUser(String name, String city, List musics, List communities) { + + if (!StringUtils.hasText(name)) { + throw new IllegalArgumentException("Name is null or empty"); + } + + UserModel user = new UserModel(name, city); + UserModel result = repo.save(user); + + updateMusics(result.getId(), musics); + return updateCommunities(user.getId(), communities); + } + + @Transactional + public UserModel addMusic(Long userId, Long musicId) { + final Optional userOpt= repo.findById(userId); + + if (userOpt.isEmpty()) { + throw new EntityNotFoundException(String.format("User with id [%s] is not found", musicId)); + } + + UserModel user = userOpt.get(); + + final Music music = musicService.findMusic(musicId); + if (music == null) { + throw new EntityNotFoundException(String.format("Music with id [%s] is not found", musicId)); + } + + user.addMusic(music); + return repo.save(user); + } + @Transactional + public UserModel addCommunity(Long userId, Long communityId) { + final Optional userOpt = repo.findById(userId); + + if (userOpt.isEmpty()) { + throw new EntityNotFoundException(String.format("User with id [%s] is not found", userId)); + } + + UserModel user = userOpt.get(); + + final Community community = communityService.findCommunity(communityId); + if (community == null) { + throw new EntityNotFoundException(String.format("Community with id [%s] is not found", communityId)); + } + + user.addCommunity(community); + return repo.save(user); + } + + @Transactional(readOnly = true) + public UserModel findUser(Long id) { + + final Optional user = repo.findById(id); + if (user.isEmpty()) { + throw new EntityNotFoundException(String.format("UserModel with id [%s] is not found", id)); + } + return user.get(); + } + +// @Transactional(readOnly = true) +// public List findUserByCity(String city){ +// Query query = repo.createQuery("select u from UserModel u where u.city = :city", +// UserModel.class).setParameter("city", city); +// List result = query.getResultList(); +// return result; +// } + @Transactional(readOnly = true) + public List findUserByCity(String city){ + List result = repo.findByCity(city); + return result; + } + + @Transactional(readOnly = true) + public List findAllUsers() { + return repo.findAll(); + } + + @Transactional + public UserModel updateUser(Long id, String name) { + + if (!StringUtils.hasText(name)) { + throw new IllegalArgumentException("User name is null or empty"); + } + final Optional currentUserOpt = repo.findById(id); + + if(currentUserOpt.isEmpty()) { + return null; + } + + final UserModel currentUser = currentUserOpt.get(); + + currentUser.setName(name); + return repo.save(currentUser); + } + //update community, musics + @Transactional + public UserModel updateUser(Long id, String name,String city, List musics, List Communities) { + if (!StringUtils.hasText(name)) { + throw new IllegalArgumentException("User name is null or empty"); + } + final Optional currentUserOpt = repo.findById(id); + + if(currentUserOpt.isEmpty()) { + return null; + } + + final UserModel currentUser = currentUserOpt.get(); + + currentUser.setName(name); + currentUser.setCity(city); + repo.save(currentUser); + + updateMusics(id, musics); + return updateCommunities(id, Communities); + } + + @Transactional + public UserModel updateCommunities(Long userId , List communities) { + final Optional userOpt = repo.findById(userId); + + if (userOpt.isEmpty()) { + throw new EntityNotFoundException(String.format("UserModel with id [%s] is not found", userId)); + } + + UserModel user = userOpt.get(); + + user.deleteCommunities(); + + for(String c : communities) { + Community community = communityService.findByName(c); + user.addCommunity(community); + } + return repo.save(user); + } + @Transactional + public UserModel updateMusics(Long userId , List musics) { + final Optional userOpt = repo.findById(userId); + + if (userOpt.isEmpty()) { + throw new EntityNotFoundException(String.format("Music with id [%s] is not found", userId)); + } + + UserModel user = userOpt.get(); + + user.deleteMusics(); + + for(String m : musics) { + Music music = musicService.findByName(m); + user.addMusic(music); + } + return repo.save(user); + } + + + @Transactional + public UserModel deleteUser(Long id) { + + final Optional currentUser = repo.findById(id); + if(currentUser.isEmpty()) { + return null; + } + + repo.deleteById(id); + return currentUser.get(); + } + + @Transactional + public void deleteAllUsers() { + repo.deleteAll(); + } + + +} diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/services/UserService.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/services/UserService.java index a3facc9..e9d1112 100644 --- a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/services/UserService.java +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/services/UserService.java @@ -1,212 +1,67 @@ package ru.ulstu.is.sbapp.socialNetwork.services; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +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.socialNetwork.models.Community; -import ru.ulstu.is.sbapp.socialNetwork.models.Music; -import ru.ulstu.is.sbapp.socialNetwork.models.UserModel; +import ru.ulstu.is.sbapp.socialNetwork.models.User; +import ru.ulstu.is.sbapp.socialNetwork.models.UserRole; import ru.ulstu.is.sbapp.socialNetwork.repository.UserRepository; +import ru.ulstu.is.sbapp.socialNetwork.util.validation.ValidationException; +import ru.ulstu.is.sbapp.socialNetwork.util.validation.ValidatorUtil; -import javax.persistence.EntityNotFoundException; -import javax.persistence.Query; -import java.util.List; -import java.util.Optional; +import java.util.Collections; +import java.util.Objects; @Service -public class UserService { +public class UserService implements UserDetailsService { + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + private final ValidatorUtil validatorUtil; - private UserRepository repo; - - private CommunityService communityService; - private MusicService musicService; - - public UserService(UserRepository repo, MusicService musicService, CommunityService communityService) { - this.repo = repo; - this.musicService = musicService; - this.communityService = communityService; + public UserService(UserRepository userRepository, + PasswordEncoder passwordEncoder, + ValidatorUtil validatorUtil) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + this.validatorUtil = validatorUtil; } - @Transactional - public UserModel addUser(String name, String city) { - if (!StringUtils.hasText(name)) { - throw new IllegalArgumentException("User name is null or empty"); - } - UserModel user = new UserModel(name, city); - return repo.save(user); - } - @Transactional - public UserModel addUser(String name, String city, List musics, List communities) { - - if (!StringUtils.hasText(name)) { - throw new IllegalArgumentException("Name is null or empty"); - } - - UserModel user = new UserModel(name, city); - UserModel result = repo.save(user); - - updateMusics(result.getId(), musics); - return updateCommunities(user.getId(), communities); + public Page findAllPages(int page, int size) { + return userRepository.findAll(PageRequest.of(page - 1, size, Sort.by("id").ascending())); } - @Transactional - public UserModel addMusic(Long userId, Long musicId) { - final Optional userOpt= repo.findById(userId); - - if (userOpt.isEmpty()) { - throw new EntityNotFoundException(String.format("User with id [%s] is not found", musicId)); - } - - UserModel user = userOpt.get(); - - final Music music = musicService.findMusic(musicId); - if (music == null) { - throw new EntityNotFoundException(String.format("Music with id [%s] is not found", musicId)); - } - - user.addMusic(music); - return repo.save(user); - } - @Transactional - public UserModel addCommunity(Long userId, Long communityId) { - final Optional userOpt = repo.findById(userId); - - if (userOpt.isEmpty()) { - throw new EntityNotFoundException(String.format("User with id [%s] is not found", userId)); - } - - UserModel user = userOpt.get(); - - final Community community = communityService.findCommunity(communityId); - if (community == null) { - throw new EntityNotFoundException(String.format("Community with id [%s] is not found", communityId)); - } - - user.addCommunity(community); - return repo.save(user); + public User findByLogin(String login) { + return userRepository.findOneByLoginIgnoreCase(login); } - @Transactional(readOnly = true) - public UserModel findUser(Long id) { - - final Optional user = repo.findById(id); - if (user.isEmpty()) { - throw new EntityNotFoundException(String.format("UserModel with id [%s] is not found", id)); - } - return user.get(); + public User createUser(String login, String password, String passwordConfirm) { + return createUser(login, password, passwordConfirm, UserRole.USER); } -// @Transactional(readOnly = true) -// public List findUserByCity(String city){ -// Query query = repo.createQuery("select u from UserModel u where u.city = :city", -// UserModel.class).setParameter("city", city); -// List result = query.getResultList(); -// return result; -// } - @Transactional(readOnly = true) - public List findUserByCity(String city){ - List result = repo.findByCity(city); - return result; + public User createUser(String login, String password, String passwordConfirm, UserRole role) { + if (findByLogin(login) != null) { + throw new ValidationException(String.format("User '%s' already exists", login)); + } + final User user = new User(login, passwordEncoder.encode(password), role); + validatorUtil.validate(user); + if (!Objects.equals(password, passwordConfirm)) { + throw new ValidationException("Passwords not equals"); + } + return userRepository.save(user); } - @Transactional(readOnly = true) - public List findAllUsers() { - return repo.findAll(); + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + final User userEntity = findByLogin(username); + if (userEntity == null) { + throw new UsernameNotFoundException(username); + } + return new org.springframework.security.core.userdetails.User( + userEntity.getLogin(), userEntity.getPassword(), Collections.singleton(userEntity.getRole())); } - - @Transactional - public UserModel updateUser(Long id, String name) { - - if (!StringUtils.hasText(name)) { - throw new IllegalArgumentException("User name is null or empty"); - } - final Optional currentUserOpt = repo.findById(id); - - if(currentUserOpt.isEmpty()) { - return null; - } - - final UserModel currentUser = currentUserOpt.get(); - - currentUser.setName(name); - return repo.save(currentUser); - } - //update community, musics - @Transactional - public UserModel updateUser(Long id, String name,String city, List musics, List Communities) { - if (!StringUtils.hasText(name)) { - throw new IllegalArgumentException("User name is null or empty"); - } - final Optional currentUserOpt = repo.findById(id); - - if(currentUserOpt.isEmpty()) { - return null; - } - - final UserModel currentUser = currentUserOpt.get(); - - currentUser.setName(name); - currentUser.setCity(city); - repo.save(currentUser); - - updateMusics(id, musics); - return updateCommunities(id, Communities); - } - - @Transactional - public UserModel updateCommunities(Long userId , List communities) { - final Optional userOpt = repo.findById(userId); - - if (userOpt.isEmpty()) { - throw new EntityNotFoundException(String.format("UserModel with id [%s] is not found", userId)); - } - - UserModel user = userOpt.get(); - - user.deleteCommunities(); - - for(String c : communities) { - Community community = communityService.findByName(c); - user.addCommunity(community); - } - return repo.save(user); - } - @Transactional - public UserModel updateMusics(Long userId , List musics) { - final Optional userOpt = repo.findById(userId); - - if (userOpt.isEmpty()) { - throw new EntityNotFoundException(String.format("Music with id [%s] is not found", userId)); - } - - UserModel user = userOpt.get(); - - user.deleteMusics(); - - for(String m : musics) { - Music music = musicService.findByName(m); - user.addMusic(music); - } - return repo.save(user); - } - - - @Transactional - public UserModel deleteUser(Long id) { - - final Optional currentUser = repo.findById(id); - if(currentUser.isEmpty()) { - return null; - } - - repo.deleteById(id); - return currentUser.get(); - } - - @Transactional - public void deleteAllUsers() { - repo.deleteAll(); - } - - } diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/util/error/AdviceController.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/util/error/AdviceController.java new file mode 100644 index 0000000..1682a3d --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/util/error/AdviceController.java @@ -0,0 +1,37 @@ +package ru.ulstu.is.sbapp.socialNetwork.util.error; + +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestController; +import ru.ulstu.is.sbapp.socialNetwork.util.validation.ValidationException; + +import java.util.stream.Collectors; + +@ControllerAdvice(annotations = RestController.class) +public class AdviceController { + @ExceptionHandler({ + ValidationException.class + }) + public ResponseEntity handleException(Throwable e) { + return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleBindException(MethodArgumentNotValidException e) { + final ValidationException validationException = new ValidationException( + e.getBindingResult().getAllErrors().stream() + .map(DefaultMessageSourceResolvable::getDefaultMessage) + .collect(Collectors.toSet())); + return handleException(validationException); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleUnknownException(Throwable e) { + e.printStackTrace(); + return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/util/validation/ValidationException.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/util/validation/ValidationException.java new file mode 100644 index 0000000..b9ab70c --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/util/validation/ValidationException.java @@ -0,0 +1,13 @@ +package ru.ulstu.is.sbapp.socialNetwork.util.validation; + +import java.util.Set; + +public class ValidationException extends RuntimeException { + public ValidationException(Set errors) { + super(String.join("\n", errors)); + } + + public ValidationException(String error) { + super(error); + } +} diff --git a/src/main/java/ru/ulstu/is/sbapp/socialNetwork/util/validation/ValidatorUtil.java b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/util/validation/ValidatorUtil.java new file mode 100644 index 0000000..d1bc372 --- /dev/null +++ b/src/main/java/ru/ulstu/is/sbapp/socialNetwork/util/validation/ValidatorUtil.java @@ -0,0 +1,27 @@ +package ru.ulstu.is.sbapp.socialNetwork.util.validation; + +import org.springframework.stereotype.Component; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.util.Set; +import java.util.stream.Collectors; + +@Component +public class ValidatorUtil { + private final Validator validator; + + public ValidatorUtil() { + this.validator = Validation.buildDefaultValidatorFactory().getValidator(); + } + + public void validate(T object) { + final Set> errors = validator.validate(object); + if (!errors.isEmpty()) { + throw new ValidationException(errors.stream() + .map(ConstraintViolation::getMessage) + .collect(Collectors.toSet())); + } + } +} diff --git a/src/main/resources/templates/login.html b/src/main/resources/templates/login.html new file mode 100644 index 0000000..019f575 --- /dev/null +++ b/src/main/resources/templates/login.html @@ -0,0 +1,30 @@ + + + +
+
+ Пользователь не найден или пароль указан не верно +
+
+ Выход успешно произведен +
+
+ Пользователь '' успешно создан +
+
+
+ +
+
+ +
+ + Регистрация +
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/signup.html b/src/main/resources/templates/signup.html new file mode 100644 index 0000000..8cd75f5 --- /dev/null +++ b/src/main/resources/templates/signup.html @@ -0,0 +1,28 @@ + + + +
+
+
+
+ +
+
+ +
+
+ +
+
+ + Назад +
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/templates/users.html b/src/main/resources/templates/users.html new file mode 100644 index 0000000..7a21a02 --- /dev/null +++ b/src/main/resources/templates/users.html @@ -0,0 +1,37 @@ + + + +
+
+ + + + + + + + + + + + + + + + + +
#IDЛогинРоль
+
+ +
+ + \ No newline at end of file diff --git a/src/test/java/ru/ulstu/is/sbapp/JpaCommunityTest.java b/src/test/java/ru/ulstu/is/sbapp/JpaCommunityTest.java index b5e3e4e..2144ae7 100644 --- a/src/test/java/ru/ulstu/is/sbapp/JpaCommunityTest.java +++ b/src/test/java/ru/ulstu/is/sbapp/JpaCommunityTest.java @@ -7,10 +7,9 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import ru.ulstu.is.sbapp.socialNetwork.models.Community; -import ru.ulstu.is.sbapp.socialNetwork.models.Music; import ru.ulstu.is.sbapp.socialNetwork.models.UserModel; import ru.ulstu.is.sbapp.socialNetwork.services.CommunityService; -import ru.ulstu.is.sbapp.socialNetwork.services.UserService; +import ru.ulstu.is.sbapp.socialNetwork.services.MyUserService; import javax.persistence.EntityNotFoundException; import java.util.List; @@ -19,7 +18,7 @@ import java.util.List; public class JpaCommunityTest { private static final Logger log = LoggerFactory.getLogger(JpaUserTest.class); @Autowired - UserService userService; + MyUserService userService; @Autowired CommunityService communityService; diff --git a/src/test/java/ru/ulstu/is/sbapp/JpaMusicTest.java b/src/test/java/ru/ulstu/is/sbapp/JpaMusicTest.java index bdff9bf..6043f1a 100644 --- a/src/test/java/ru/ulstu/is/sbapp/JpaMusicTest.java +++ b/src/test/java/ru/ulstu/is/sbapp/JpaMusicTest.java @@ -8,7 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import ru.ulstu.is.sbapp.socialNetwork.models.Music; import ru.ulstu.is.sbapp.socialNetwork.services.MusicService; -import ru.ulstu.is.sbapp.socialNetwork.services.UserService; +import ru.ulstu.is.sbapp.socialNetwork.services.MyUserService; import javax.persistence.EntityNotFoundException; import java.util.List; @@ -17,7 +17,7 @@ import java.util.List; public class JpaMusicTest { private static final Logger log = LoggerFactory.getLogger(JpaUserTest.class); @Autowired - UserService userService; + MyUserService userService; @Autowired MusicService musicService; diff --git a/src/test/java/ru/ulstu/is/sbapp/JpaUserTest.java b/src/test/java/ru/ulstu/is/sbapp/JpaUserTest.java index 2536bac..6a9211a 100644 --- a/src/test/java/ru/ulstu/is/sbapp/JpaUserTest.java +++ b/src/test/java/ru/ulstu/is/sbapp/JpaUserTest.java @@ -11,7 +11,7 @@ import ru.ulstu.is.sbapp.socialNetwork.models.Music; import ru.ulstu.is.sbapp.socialNetwork.models.UserModel; import ru.ulstu.is.sbapp.socialNetwork.services.CommunityService; import ru.ulstu.is.sbapp.socialNetwork.services.MusicService; -import ru.ulstu.is.sbapp.socialNetwork.services.UserService; +import ru.ulstu.is.sbapp.socialNetwork.services.MyUserService; import javax.persistence.EntityNotFoundException; import java.util.List; @@ -20,7 +20,7 @@ import java.util.List; public class JpaUserTest { private static final Logger log = LoggerFactory.getLogger(JpaUserTest.class); @Autowired - UserService userService; + MyUserService userService; @Autowired MusicService musicService;