Răsfoiți Sursa

register user logic with backend validation

mateuszsudra 2 ani în urmă
părinte
comite
d9a967848e

+ 13 - 0
boat-reservation-logic/pom.xml

@@ -125,6 +125,19 @@
             <artifactId>jakarta.mail</artifactId>
             <version>2.0.1</version>
         </dependency>
+        <!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-jwt -->
+        <dependency>
+            <groupId>org.springframework.security</groupId>
+            <artifactId>spring-security-jwt</artifactId>
+            <version>1.1.1.RELEASE</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+            <version>6.0.9</version>
+        </dependency>
+
     </dependencies>
 
 

+ 7 - 0
boat-reservation-logic/src/main/java/pl/sudra/configuration/SpringConfiguration.java

@@ -6,6 +6,8 @@ import org.springframework.context.annotation.ComponentScan;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.support.ReloadableResourceBundleMessageSource;
 import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
 import org.springframework.web.servlet.LocaleResolver;
 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@@ -72,6 +74,11 @@ public class SpringConfiguration implements WebMvcConfigurer {
         return bean;
     }
 
+    @Bean
+    public PasswordEncoder passwordEncoder() {
+        return new BCryptPasswordEncoder();
+    }
+
 //    @Resource(name = "addressService")
 //    private AddressService addressService;
 //

+ 2 - 0
boat-reservation-logic/src/main/java/pl/sudra/controller/UserController.java

@@ -1,4 +1,6 @@
 package pl.sudra.controller;
 
+import pl.sudra.service.ReservationService;
+
 public class UserController {
 }

+ 80 - 0
boat-reservation-logic/src/main/java/pl/sudra/domain/User.java

@@ -1,4 +1,84 @@
 package pl.sudra.domain;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import jakarta.persistence.*;
+import jakarta.validation.Constraint;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+
+@Entity
 public class User {
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    private Long id;
+    @Column(unique = true)
+    @NotNull
+    @NotBlank(message = "Username is required")
+    @Size(message = "Username must be between 6 and 20 characters", min = 6, max = 20)
+    private String username;
+
+    //    @JsonIgnore
+    @NotNull
+    @NotBlank(message = "Password is required")
+    private String password;
+    @Column(unique = true)
+    @NotNull
+    @NotBlank(message = "Email is required")
+    @Email(regexp = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$", message = "Invalid email address")
+    private String email;
+
+    private String role = "USER";
+
+    public User() {
+    }
+
+    public User(Long id, String username, String password, String email, String role) {
+        this.id = id;
+        this.username = username;
+        this.password = password;
+        this.email = email;
+        this.role = role;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public String getRole() {
+        return role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
 }

+ 9 - 1
boat-reservation-logic/src/main/java/pl/sudra/repository/UserRepository.java

@@ -1,4 +1,12 @@
 package pl.sudra.repository;
 
-public interface UserRepository {
+import org.springframework.data.jpa.repository.JpaRepository;
+import pl.sudra.domain.User;
+
+import java.util.Optional;
+
+public interface UserRepository extends JpaRepository<User, Long> {
+    Optional<User> findByUsername(String username);
+
+    Optional<User> findByEmail(String email);
 }

+ 72 - 0
boat-reservation-logic/src/main/java/pl/sudra/securityController/SecurityController.java

@@ -0,0 +1,72 @@
+package pl.sudra.securityController;
+
+
+import jakarta.validation.Valid;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+import pl.sudra.domain.User;
+import pl.sudra.service.UserService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+//import pl.sudra.configuration.SpringConfiguration.PasswordEncoder;
+import org.springframework.context.support.DefaultMessageSourceResolvable;
+
+@RestController
+@CrossOrigin(origins = "http://localhost:1410")
+public class SecurityController {
+    private UserService userService;
+    @Autowired
+    private PasswordEncoder passwordEncoder;
+
+    public SecurityController(UserService userService) {
+        this.userService = userService;
+    }
+
+    @RequestMapping(
+            value = "/register",
+            method = RequestMethod.POST,
+            produces = MediaType.APPLICATION_JSON_VALUE)
+    public ResponseEntity<?> Register(@Valid @RequestBody User user, BindingResult bindingResult) {
+        if (bindingResult.hasErrors()) {
+            List<String> errors = bindingResult.getAllErrors()
+                    .stream()
+                    .map(DefaultMessageSourceResolvable::getDefaultMessage)
+                    .collect(Collectors.toList());
+
+            ValidationErrorResponse errorResponse = new ValidationErrorResponse();
+            errorResponse.setMessage("Validation Error");
+            errorResponse.setErrors(errors);
+
+            return ResponseEntity.badRequest().body(errorResponse);
+        }
+
+        boolean isUsernameNotUnique = this.userService.isUsernameNotUnique(user.getUsername());
+        boolean isEmailNotUnique = this.userService.isEmailNotUnique(user.getEmail());
+
+        if (isUsernameNotUnique || isEmailNotUnique) {
+            ValidationErrorResponse errorResponse = new ValidationErrorResponse();
+            errorResponse.setMessage("Duplication Error");
+            List<String> errors = new ArrayList<>();
+            if(isUsernameNotUnique) errors.add("Username already exist in database.");
+            if(isEmailNotUnique) errors.add("Email already exist in database.");
+            errorResponse.setErrors(errors);
+
+            return ResponseEntity.badRequest().body(errorResponse);
+        }
+        System.out.println("Creating reservation");
+
+        String hashedPassword = passwordEncoder.encode(user.getPassword());
+        user.setPassword(hashedPassword);
+
+        this.userService.registerUser(user);
+
+        return ResponseEntity.ok("Request is valid");
+    }
+
+}

+ 10 - 0
boat-reservation-logic/src/main/java/pl/sudra/service/UserService.java

@@ -0,0 +1,10 @@
+package pl.sudra.service;
+
+import pl.sudra.domain.User;
+
+public interface UserService {
+    void registerUser(User user);
+
+    boolean isEmailNotUnique(String email);
+    boolean isUsernameNotUnique(String username);
+}

+ 31 - 0
boat-reservation-logic/src/main/java/pl/sudra/service/UserServiceImpl.java

@@ -0,0 +1,31 @@
+package pl.sudra.service;
+
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import pl.sudra.domain.User;
+import pl.sudra.repository.UserRepository;
+
+@Service("userService")
+@Transactional
+public class UserServiceImpl implements UserService {
+    private final UserRepository userRepository;
+
+    public UserServiceImpl(UserRepository userRepository) {
+        this.userRepository = userRepository;
+    }
+
+    @Override
+    public void registerUser(User user) {
+        this.userRepository.save(user);
+    }
+
+    @Override
+    public boolean isEmailNotUnique(String email) {
+        return this.userRepository.findByEmail(email).isPresent();
+    }
+
+    @Override
+    public boolean isUsernameNotUnique(String username) {
+        return this.userRepository.findByUsername(username).isPresent();
+    }
+}

+ 32 - 0
boat-reservation-view/src/app/login-view/login-view.component.css

@@ -0,0 +1,32 @@
+form {
+  width: 300px;
+  margin: 0 auto;
+}
+
+label {
+  display: block;
+  margin-bottom: 8px;
+}
+
+input[type="text"],
+input[type="number"],
+textarea {
+  width: 100%;
+  padding: 8px;
+  margin-bottom: 16px;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+}
+
+input[type="submit"] {
+  background-color: #4caf50;
+  color: #fff;
+  padding: 10px 16px;
+  border: none;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+input[type="submit"]:hover {
+  background-color: #45a049;
+}

+ 21 - 6
boat-reservation-view/src/app/login-view/login-view.component.html

@@ -1,7 +1,22 @@
+<div style="text-align: center;font-family: Courier New, monospace;">
+  <div style="text-align: center;">
+    <h2>LOGIN</h2>
+  </div>
+  <form (submit)="login()" #myForm="ngForm">
+    <label for="username" style="text-align: left;">Username:</label>
+    <input type="text"
+           id="username"
+           name="name" [(ngModel)]="formData.name" required>
 
-Don't have an account?
-<a class="navbar-button"
-   routerLink="/register"
-   routerLinkActive="activebutton">
-  REGISTER HERE
-</a>
+    <label for="password" style="text-align: left;">Password:</label>
+    <input type="text"
+           id="password"
+           name="name" [(ngModel)]="formData.password" required>
+
+    <input type="submit" value="Login">
+  </form>
+  <br>
+  <p> Don't have an account?</p>
+  <input type="submit" value="REGISTER HERE" routerLink="/register" routerLinkActive="activebutton">
+  <br><br>
+</div>

+ 4 - 0
boat-reservation-view/src/app/login-view/login-view.component.ts

@@ -6,5 +6,9 @@ import { Component } from '@angular/core';
   styleUrls: ['./login-view.component.css']
 })
 export class LoginViewComponent {
+  formData: any = {};
 
+  login() {
+    console.log("login attempt")
+  }
 }

+ 13 - 13
boat-reservation-view/src/app/register-view/register-view.component.html

@@ -1,22 +1,22 @@
 <div style="text-align: center;">
-  <h2>REGISTER NEW BOAT</h2>
+  <h2>REGISTER NEW USER</h2>
 </div>
-<form (submit)="addBoat()" #myForm="ngForm">
-  <label for="name">Name:</label>
+<form (submit)="registerUser()" #myForm="ngForm" style="font-family: Courier New, monospace;">
+  <label for="username">Username:</label>
   <input type="text"
-         id="name"
+         id="username"
          name="name" [(ngModel)]="formData.name" required>
 
-  <label for="capacity">Capacity:</label>
-  <input type="number"
-         id="capacity"
-         name="capacity" [(ngModel)]="formData.capacity" required>
+  <label for="password">Password:</label>
+  <input type="text"
+         id="password"
+         name="name" [(ngModel)]="formData.password" required>
 
-  <label for="cost">Cost:</label>
-  <input type="number"
-         id="cost"
-         name="cost" [(ngModel)]="formData.cost" required>
+  <label for="email">Email:</label>
+  <input type="text"
+         id="email"
+         name="name" [(ngModel)]="formData.email" required>
 
-  <input type="submit" value="Submit">
+  <input type="submit" value="Register">
 </form>
 

+ 3 - 9
boat-reservation-view/src/app/register-view/register-view.component.ts

@@ -1,5 +1,4 @@
 import {Component} from '@angular/core';
-import {BoatsService} from "../boats-service/boats.service";
 
 @Component({
   selector: 'app-register-view',
@@ -9,16 +8,11 @@ import {BoatsService} from "../boats-service/boats.service";
 export class RegisterViewComponent {
   formData: any = {};
 
-  constructor(private boatService: BoatsService) {
+  constructor() {
   }
 
-  addBoat() {
-    let boat_info  = {
-      "name": this.formData.name,
-      "capacity": this.formData.capacity,
-      "cost": this.formData.cost,
-    }
+  registerUser() {
+    console.log("register attempt")
 
-    this.boatService.addBoat(boat_info)
   }
 }