From 3ea4cd2f9b3808ef645092816d888de406580e6d Mon Sep 17 00:00:00 2001 From: realtradam Date: Sat, 13 Jul 2024 00:28:07 -0400 Subject: implement user registration --- pom.xml | 4 ++ .../blog/web/controllers/ArticleController.java | 6 +- .../com/blog/web/controllers/AuthController.java | 64 ++++++++++++++++++++++ .../java/com/blog/web/dto/RegistrationDto.java | 18 ++++++ src/main/java/com/blog/web/models/Role.java | 26 +++++++++ src/main/java/com/blog/web/models/UserEntity.java | 32 +++++++++++ .../com/blog/web/repository/RoleRepository.java | 8 +++ .../com/blog/web/repository/UserRepository.java | 9 +++ .../java/com/blog/web/services/ArticleService.java | 1 + .../java/com/blog/web/services/UserService.java | 13 +++++ .../blog/web/services/impl/UserServiceImpl.java | 46 ++++++++++++++++ src/main/resources/application.properties | 2 + src/main/resources/templates/auth/login.html | 48 ++++++++++++++++ src/main/resources/templates/auth/register.html | 63 +++++++++++++++++++++ src/main/resources/templates/index.html | 2 + src/main/resources/templates/layout.html | 4 +- 16 files changed, 341 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/blog/web/controllers/AuthController.java create mode 100644 src/main/java/com/blog/web/dto/RegistrationDto.java create mode 100644 src/main/java/com/blog/web/models/Role.java create mode 100644 src/main/java/com/blog/web/models/UserEntity.java create mode 100644 src/main/java/com/blog/web/repository/RoleRepository.java create mode 100644 src/main/java/com/blog/web/repository/UserRepository.java create mode 100644 src/main/java/com/blog/web/services/UserService.java create mode 100644 src/main/java/com/blog/web/services/impl/UserServiceImpl.java create mode 100644 src/main/resources/templates/auth/login.html create mode 100644 src/main/resources/templates/auth/register.html diff --git a/pom.xml b/pom.xml index 7ceafb8..d5af752 100644 --- a/pom.xml +++ b/pom.xml @@ -72,6 +72,10 @@ org.springframework.boot spring-boot-starter-validation + + org.springframework.boot + spring-boot-starter-security + diff --git a/src/main/java/com/blog/web/controllers/ArticleController.java b/src/main/java/com/blog/web/controllers/ArticleController.java index 0cdff15..fc18dd7 100644 --- a/src/main/java/com/blog/web/controllers/ArticleController.java +++ b/src/main/java/com/blog/web/controllers/ArticleController.java @@ -20,7 +20,7 @@ public class ArticleController { this.articleService = articleService; } - @GetMapping("/") + @GetMapping("/articles") public String listArticles(Model model) { List articles = articleService.findAllArticles(); model.addAttribute("articles", articles); @@ -85,8 +85,8 @@ public class ArticleController { return "index"; } - @GetMapping("/articles") + @GetMapping("/") public String getArticles() { - return "redirect:/"; + return "redirect:/articles"; } } diff --git a/src/main/java/com/blog/web/controllers/AuthController.java b/src/main/java/com/blog/web/controllers/AuthController.java new file mode 100644 index 0000000..bb7cb0d --- /dev/null +++ b/src/main/java/com/blog/web/controllers/AuthController.java @@ -0,0 +1,64 @@ +package com.blog.web.controllers; + +import com.blog.web.dto.RegistrationDto; +import com.blog.web.models.UserEntity; +import com.blog.web.services.UserService; +import jakarta.validation.Valid; +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; + +@Controller +public class AuthController { + private UserService userService; + + public AuthController(UserService userService) { + this.userService = userService; + } + + @GetMapping("/login") + public String loginPage() { + return "auth/login"; + } + + @GetMapping("/register") + public String getRegisterForm(Model model) { + RegistrationDto user = new RegistrationDto(); + model.addAttribute("user", user); + return "auth/register"; + } + + @PostMapping("/register/save") + public String register(@Valid @ModelAttribute("user")RegistrationDto user, + BindingResult result, + Model model) { + UserEntity existingUserEmail = userService.findByEmail(user.getEmail()); + if( + existingUserEmail != null && + existingUserEmail.getEmail() != null && + !existingUserEmail.getEmail().isEmpty() + ) { + result.rejectValue("email", "There is already a user with this email"); + } + + UserEntity existingUsername = userService.findByUsername(user.getUsername()); + if( + existingUsername != null && + existingUsername.getUsername() != null && + !existingUsername.getUsername().isEmpty() + ) + { + result.rejectValue("username", "There is already a user with this username"); + } + + if(result.hasErrors()) { + model.addAttribute("user", user); + return "register"; + } + userService.saveUser(user); + return "redirect:/articles?success"; + } +} diff --git a/src/main/java/com/blog/web/dto/RegistrationDto.java b/src/main/java/com/blog/web/dto/RegistrationDto.java new file mode 100644 index 0000000..1682c5c --- /dev/null +++ b/src/main/java/com/blog/web/dto/RegistrationDto.java @@ -0,0 +1,18 @@ +package com.blog.web.dto; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotEmpty; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; + +@Data +public class RegistrationDto { + private Long id; + @NotEmpty + private String username; + @NotEmpty + private String email; + @NotEmpty + private String password; +} diff --git a/src/main/java/com/blog/web/models/Role.java b/src/main/java/com/blog/web/models/Role.java new file mode 100644 index 0000000..b04c9d8 --- /dev/null +++ b/src/main/java/com/blog/web/models/Role.java @@ -0,0 +1,26 @@ +package com.blog.web.models; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.apache.catalina.User; + +import java.sql.Array; +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity(name = "roles") +public class Role { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String name; + @ManyToMany(mappedBy = "roles") + private List users = new ArrayList<>(); +} diff --git a/src/main/java/com/blog/web/models/UserEntity.java b/src/main/java/com/blog/web/models/UserEntity.java new file mode 100644 index 0000000..2dfb036 --- /dev/null +++ b/src/main/java/com/blog/web/models/UserEntity.java @@ -0,0 +1,32 @@ +package com.blog.web.models; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Entity(name = "users") +// Named UserEntity to prevent conflicts with Java User object +public class UserEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String username; + private String email; + private String password; + @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL) + @JoinTable( + name = "user_roles", + joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")}, + inverseJoinColumns = {@JoinColumn(name = "role_id", referencedColumnName = "id")} + ) + private List roles = new ArrayList<>(); +} diff --git a/src/main/java/com/blog/web/repository/RoleRepository.java b/src/main/java/com/blog/web/repository/RoleRepository.java new file mode 100644 index 0000000..08c9ef4 --- /dev/null +++ b/src/main/java/com/blog/web/repository/RoleRepository.java @@ -0,0 +1,8 @@ +package com.blog.web.repository; + +import com.blog.web.models.Role; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RoleRepository extends JpaRepository { + Role findByName(String name); +} diff --git a/src/main/java/com/blog/web/repository/UserRepository.java b/src/main/java/com/blog/web/repository/UserRepository.java new file mode 100644 index 0000000..af67f58 --- /dev/null +++ b/src/main/java/com/blog/web/repository/UserRepository.java @@ -0,0 +1,9 @@ +package com.blog.web.repository; + +import com.blog.web.models.UserEntity; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserRepository extends JpaRepository { + UserEntity findByEmail(String email); + UserEntity findByUsername(String username); +} diff --git a/src/main/java/com/blog/web/services/ArticleService.java b/src/main/java/com/blog/web/services/ArticleService.java index 9cab70b..2c1e9f4 100644 --- a/src/main/java/com/blog/web/services/ArticleService.java +++ b/src/main/java/com/blog/web/services/ArticleService.java @@ -5,6 +5,7 @@ import com.blog.web.models.Article; import java.util.List; + public interface ArticleService { List findAllArticles(); diff --git a/src/main/java/com/blog/web/services/UserService.java b/src/main/java/com/blog/web/services/UserService.java new file mode 100644 index 0000000..8515cb1 --- /dev/null +++ b/src/main/java/com/blog/web/services/UserService.java @@ -0,0 +1,13 @@ +package com.blog.web.services; + +import com.blog.web.dto.RegistrationDto; +import com.blog.web.models.UserEntity; + + +public interface UserService { + void saveUser(RegistrationDto registrationDto); + + UserEntity findByEmail(String email); + + UserEntity findByUsername(String username); +} diff --git a/src/main/java/com/blog/web/services/impl/UserServiceImpl.java b/src/main/java/com/blog/web/services/impl/UserServiceImpl.java new file mode 100644 index 0000000..06dbc22 --- /dev/null +++ b/src/main/java/com/blog/web/services/impl/UserServiceImpl.java @@ -0,0 +1,46 @@ +package com.blog.web.services.impl; + +import com.blog.web.dto.RegistrationDto; +import com.blog.web.models.Role; +import com.blog.web.models.UserEntity; +import com.blog.web.repository.RoleRepository; +import com.blog.web.repository.UserRepository; +import com.blog.web.services.UserService; +import org.springframework.stereotype.Service; + +import java.util.Arrays; + +@Service +public class UserServiceImpl implements UserService { + private UserRepository userRepository; + private RoleRepository roleRepository; + + public UserServiceImpl(UserRepository userRepository, RoleRepository roleRepository) { + this.userRepository = userRepository; + this.roleRepository = roleRepository; + } + + @Override + public void saveUser(RegistrationDto registrationDto) { + UserEntity user = new UserEntity(); + user.setUsername(registrationDto.getUsername()); + user.setEmail(registrationDto.getEmail()); + // this is an unsafe way to store passwords in production + // it is left this way only because this is a practice project + user.setPassword(registrationDto.getPassword()); + + Role role = roleRepository.findByName("User"); + user.setRoles(Arrays.asList(role)); + userRepository.save(user); + } + + @Override + public UserEntity findByEmail(String email) { + return userRepository.findByEmail(email); + } + + @Override + public UserEntity findByUsername(String username) { + return userRepository.findByUsername(username); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 45084fa..8cc70a2 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,3 +5,5 @@ spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true + +sprint.security.user.password=test diff --git a/src/main/resources/templates/auth/login.html b/src/main/resources/templates/auth/login.html new file mode 100644 index 0000000..aee1594 --- /dev/null +++ b/src/main/resources/templates/auth/login.html @@ -0,0 +1,48 @@ + + + + +
Invalid Username/Password
+
You have been logged out
+ +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/auth/register.html b/src/main/resources/templates/auth/register.html new file mode 100644 index 0000000..4f8fd44 --- /dev/null +++ b/src/main/resources/templates/auth/register.html @@ -0,0 +1,63 @@ + + + + +
+
Username or Email already exists
+
+
+
+ + +

Please fill out this field.

+
+
+ + +

Please fill out this field.

+
+
+
+
+ + +

Please fill out this field.

+
+
+
+
+ + +
+
+ + + \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 1dcef48..ea12d7e 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -76,6 +76,8 @@ +
Successful Registration!
+
diff --git a/src/main/resources/templates/layout.html b/src/main/resources/templates/layout.html index 17d6939..a5bdb2c 100644 --- a/src/main/resources/templates/layout.html +++ b/src/main/resources/templates/layout.html @@ -42,10 +42,10 @@ NEW
  • - LINK + REGISTER
  • - LINK + LOGIN
  • -- cgit v1.2.3