Browse Source

RIFFMASTER: BACKEND: add registration endpoint (no roles added)

Kuba 2 năm trước cách đây
mục cha
commit
e094ca3095
69 tập tin đã thay đổi với 382 bổ sung31 xóa
  1. 19 4
      Backend/Spring/.idea/workspace.xml
  2. 19 1
      Backend/Spring/pom.xml
  3. 1 0
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.java
  4. 132 0
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/controller/SecurityController.java
  5. 17 5
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/domain/AppUser.java
  6. 30 0
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/domain/LoginEntity.java
  7. 1 0
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/repository/IAppUserRepository.java
  8. 72 0
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/security/JwtTokenUtil.java
  9. 32 0
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/security/ValidationErrorResponse.java
  10. 13 1
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/service/AppUserService.java
  11. 3 0
      Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/service/IAppUserService.java
  12. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.class
  13. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/controller/SecurityController.class
  14. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/domain/AppUser.class
  15. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/domain/LoginEntity.class
  16. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/repository/IAppUserRepository.class
  17. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/security/JwtTokenUtil.class
  18. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/security/ValidationErrorResponse.class
  19. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/service/AppUserService.class
  20. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/service/IAppUserService.class
  21. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/lib/jjwt-api-0.11.2.jar
  22. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/lib/jjwt-impl-0.11.2.jar
  23. BIN
      Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/lib/jjwt-jackson-0.11.2.jar
  24. BIN
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.class
  25. BIN
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/controller/SecurityController.class
  26. BIN
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/domain/AppUser.class
  27. BIN
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/domain/LoginEntity.class
  28. BIN
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/repository/IAppUserRepository.class
  29. BIN
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/security/JwtTokenUtil.class
  30. BIN
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/security/ValidationErrorResponse.class
  31. BIN
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/service/AppUserService.class
  32. BIN
      Backend/Spring/target/classes/pl/dmcs/jwoszczyk/service/IAppUserService.class
  33. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/0.pack
  34. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/10.pack
  35. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/11.pack
  36. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/12.pack
  37. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/13.pack
  38. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/15.pack
  39. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/2.pack
  40. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/8.pack
  41. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/9.pack
  42. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack
  43. BIN
      Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack.old
  44. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/22e6c567cfca28eb7499f46f4707c3c1df18f6792a58a069008129af90af343c.json
  45. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/32f09522d15475a3c0671946c675aba8c907c1569ddc421aee9e0424e3ef4bf1.json
  46. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/42bf7d83d8be32482d3377527c339d0d776a5cf597791f7d975c657939b27ffa.json
  47. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/44d182aa5f83201cd731ad535f3921584d4e0b78b9cac185c0f6fc3b6111b5a2.json
  48. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/489d688920706c7b7e66f2c4da10a5b535b52e9dc6ce152e352f7d1b409b86b6.json
  49. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/4ec5d74cc9a5367a0f0134830672622c0c4246925c11f173362eb663f54b04b1.json
  50. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/57ca0e53e220db86f09f1b327f9123d8491524a93553c95743715ff5564417ba.json
  51. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/67cd29cb035aeee396e161c6f8722cdbf7d565a5e863508062a76bb7e87b9f2f.json
  52. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/8e64a916e9ad0b41511e572c0bd1e5f5b10e9bff9e83a281fa856ab15fa2de64.json
  53. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/92b8c5328812235b1dcf7fa157cbf66e614041571440fa067ecccdbb86e17c35.json
  54. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/92ec7098907310877ebce08a42cc2842e33bce393123a5e3a71e222a9e54f32a.json
  55. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/9ba82840f7b232bb2beae4e3a04f2917c1f129e2ce252b1ef656bcb3ac716af3.json
  56. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/a5b505edf5d8e36ffc5d6453ca1eafb6e5ca9d6ed588f380eadfe57f9e6398c8.json
  57. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/a69e0865ce26a24232478dbfdd93704f0d6a61040339da0b87adc3e1bd831fde.json
  58. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/b15a76dbfb86e8779160b5302f1ff11cb2278415f8007a5f8d7c2b14ed3ffb9c.json
  59. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/b35cdb46a32d5dea2bd82c47ad045e89e99c212361d75c10aaf52666d313ebf6.json
  60. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/bd230926c726c01c4979dcc29aff8769e8e57d37925c17b2025019b3e0f7a780.json
  61. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/c6ba7c6da31bd668c3d09b7e81d5d8482b9ce32dec72db1764045cc8d80111d6.json
  62. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/d8ab847f5d54b54108722462a7edc2fde8bb0b6ab2c4232008759714e3d56828.json
  63. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/e0d27c666f96fe84e02390b10a23c8b9266de7537ebd326dc3b6443b01cb322c.json
  64. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/e3e25b63fbcf9714dbc4d2c93eb7b4e833a2e4237bf020dac0b31f502711db05.json
  65. 0 0
      Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/e507b3240d4fdce8578d42bb3d83aa0440517fe86fa55a09fa3f91f6c264be1c.json
  66. 32 17
      Frontend/RiffMasterFront/.idea/workspace.xml
  67. 7 2
      Frontend/RiffMasterFront/src/app/main-page/main-page.component.css
  68. 1 1
      Frontend/RiffMasterFront/src/app/main-page/main-page.component.html
  69. 3 0
      Frontend/RiffMasterFront/src/app/main-page/main-page.component.ts

+ 19 - 4
Backend/Spring/.idea/workspace.xml

@@ -10,7 +10,21 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="8315de53-8c15-472c-a710-45938463dc02" name="Changes" comment="RIFFMASTER: add frontend files">
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/0.pack" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/0.pack" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/10.pack" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/10.pack" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/11.pack" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/11.pack" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/12.pack" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/12.pack" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/13.pack" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/13.pack" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/15.pack" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/15.pack" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/2.pack" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/2.pack" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/8.pack" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/8.pack" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/9.pack" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/9.pack" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack.old" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack.old" afterDir="false" />
       <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/.idea/workspace.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/src/app/main-page/main-page.component.css" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/src/app/main-page/main-page.component.css" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/src/app/main-page/main-page.component.html" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/src/app/main-page/main-page.component.html" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/src/app/main-page/main-page.component.ts" beforeDir="false" afterPath="$PROJECT_DIR$/../../Frontend/RiffMasterFront/src/app/main-page/main-page.component.ts" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -82,11 +96,11 @@
       <recent name="C:\Users\Quba\Desktop\studia\WPFt\Spring\src\main\webapp" />
     </key>
     <key name="CopyClassDialog.RECENTS_KEY">
-      <recent name="pl.dmcs.jwoszczyk.configuration" />
+      <recent name="pl.dmcs.jwoszczyk.security" />
       <recent name="pl.dmcs.jwoszczyk.domain" />
-      <recent name="pl.dmcs.jwoszczyk.service" />
       <recent name="pl.dmcs.jwoszczyk.controller" />
-      <recent name="pl.dmcs.jwoszczyk.repository" />
+      <recent name="pl.dmcs.jwoszczyk.configuration" />
+      <recent name="pl.dmcs.jwoszczyk.service" />
     </key>
   </component>
   <component name="RunManager">
@@ -217,7 +231,8 @@
       <workItem from="1686937489475" duration="803000" />
       <workItem from="1686986592460" duration="4445000" />
       <workItem from="1687000973157" duration="670000" />
-      <workItem from="1687006511411" duration="599000" />
+      <workItem from="1687006511411" duration="604000" />
+      <workItem from="1687011079341" duration="7518000" />
     </task>
     <task id="LOCAL-00001" summary="add basic hello world and transfering data to server">
       <created>1679575346987</created>

+ 19 - 1
Backend/Spring/pom.xml

@@ -149,8 +149,26 @@
             <version>2.0.1</version>
         </dependency>
 
-        <!--################################################################_-->
+        <!--################################################################_JWT-->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-api</artifactId>
+            <version>0.11.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-impl</artifactId>
+            <version>0.11.2</version>
+            <scope>runtime</scope>
+        </dependency>
 
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt-jackson</artifactId>
+            <version>0.11.2</version>
+            <scope>runtime</scope>
+        </dependency>
 
         <!--################################################################_-->
 

+ 1 - 0
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.java

@@ -91,6 +91,7 @@ public class SecurityConfiguration {
                         .requestMatchers("/exampleTwo*").hasAnyAuthority("ROLE_STUDENT", "ROLE_ADMIN")
                         .requestMatchers("/exampleThree*").hasRole("STUDENT")
                         .requestMatchers("/login*").anonymous()
+                        .requestMatchers("/register*").anonymous()
                         .anyRequest().authenticated()
                 )
                 .formLogin(form -> form

+ 132 - 0
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/controller/SecurityController.java

@@ -0,0 +1,132 @@
+package pl.dmcs.jwoszczyk.controller;
+
+import jakarta.validation.Valid;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.support.DefaultMessageSourceResolvable;
+import org.springframework.http.HttpStatus;
+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.dmcs.jwoszczyk.domain.AppUser;
+import pl.dmcs.jwoszczyk.domain.AppUserRole;
+import pl.dmcs.jwoszczyk.domain.LoginEntity;
+import pl.dmcs.jwoszczyk.security.JwtTokenUtil;
+import pl.dmcs.jwoszczyk.security.ValidationErrorResponse;
+import pl.dmcs.jwoszczyk.service.IAppUserService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@RestController
+@CrossOrigin(origins = "http://localhost:4200")
+public class SecurityController {
+    private IAppUserService userService;
+    @Autowired
+    private PasswordEncoder passwordEncoder;
+
+    public SecurityController(IAppUserService userService) {
+        this.userService = userService;
+    }
+
+    @RequestMapping(value = "/register", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
+    public ResponseEntity<?> Register(@Valid @RequestBody AppUser user, BindingResult bindingResult)
+    {
+        // validation check
+        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);
+        }
+        // duplication check
+        boolean usernameUnique = this.userService.isUsernameUnique(user.getLogin());
+        boolean emailUnique = this.userService.isEmailUnique(user.getEmail());
+
+        if (!usernameUnique || !emailUnique)
+        {
+            ValidationErrorResponse errorResponse = new ValidationErrorResponse();
+            errorResponse.setMessage("Duplication Error");
+            List<String> errors = new ArrayList<>();
+            if (!usernameUnique) errors.add("Username already exist in database.");
+            if (!emailUnique) errors.add("Email already exist in database.");
+            errorResponse.setErrors(errors);
+
+            return ResponseEntity.badRequest().body(errorResponse);
+        }
+
+        String hashedPassword = passwordEncoder.encode(user.getPassword());
+        user.setPassword(hashedPassword);
+
+        this.userService.registerUser(user);
+
+        return ResponseEntity
+                .status(HttpStatus.OK)
+                .body("{\"message\": \"Request is valid\"}");
+    }
+
+    @RequestMapping(value = "/login", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
+    public ResponseEntity<?> Login(@Valid @RequestBody LoginEntity loginEntity)
+    {
+        Optional<AppUser> user = Optional.ofNullable(this.userService.findByLogin(loginEntity.getUsername()));
+
+        if (user.isEmpty())
+        {
+            ValidationErrorResponse errorResponse = new ValidationErrorResponse();
+            errorResponse.setMessage("Login Error");
+            List<String> errors = new ArrayList<>();
+            errors.add("No such username in database.");
+            errorResponse.setErrors(errors);
+
+            return ResponseEntity.badRequest().body(errorResponse);
+        }
+        else
+        {
+            if (passwordEncoder.matches(loginEntity.getPassword(), user.get().getPassword()))
+            {
+                System.out.println("Login successful");
+                String jwtToken = JwtTokenUtil.generateToken(
+                        user.get().getLogin(),
+                        user.get().getAppUserRoleStringArray()
+                );
+                System.out.println(jwtToken);
+
+//                return ResponseEntity.ok()
+//                        .header("Authorization", "Bearer " + jwtToken)
+//                        .body("Request is valid");
+
+                return ResponseEntity
+                        .status(HttpStatus.OK)
+                        .header("Authorization", "Bearer " + jwtToken)
+                        .body("{\"message\": \"Request is valid\"," +
+                                "\"Authorization\": \"Bearer " + jwtToken + "\"}");
+            } else {
+                ValidationErrorResponse errorResponse = new ValidationErrorResponse();
+                errorResponse.setMessage("Login Error");
+                List<String> errors = new ArrayList<>();
+                errors.add("Password is not matching.");
+                errorResponse.setErrors(errors);
+
+                return ResponseEntity.badRequest().body(errorResponse);
+            }
+
+        }
+
+
+
+    }
+
+
+
+
+}

+ 17 - 5
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/domain/AppUser.java

@@ -1,6 +1,8 @@
 package pl.dmcs.jwoszczyk.domain;
 
 import jakarta.persistence.*;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotNull;
 import jakarta.validation.constraints.Size;
 
@@ -18,24 +20,25 @@ public class AppUser {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     long id;
-    @NotNull
-    @Column(name = "firstName", nullable = false)
+    @Column(name = "firstName")
     @Size(min=2, max=30, message = "{error.size.firstName}")
     private String firstName;
-    @NotNull
     @Size(min=2, max=30)
     private String lastName;
     @NotNull
+    @NotBlank(message = "Email is required")
+    @Email(regexp = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$", message = "Invalid email address")
     private String email;
     @Size(min=9, max=9)
     private String telephone;
 
     //#####################################################################_security
     @NotNull
-    @Column(unique = true)
+    @NotBlank(message = "Username is required")
+    @Size(message = "Username must be between 5 and 20 characters", min = 4, max = 20)
     private String login;
-    @JsonIgnore
     @NotNull
+    @NotBlank(message = "Password is required")
     private String password;
     private boolean enabled;
     @ManyToMany(fetch = FetchType.EAGER)
@@ -99,6 +102,15 @@ public class AppUser {
     public Set<AppUserRole> getAppUserRole() {
         return appUserRole;
     }
+    public String[] getAppUserRoleStringArray() {
+        Set<AppUserRole> appUserRoles = getAppUserRole(); // Assuming you have a method to retrieve the Set<AppUserRole>
+
+        String[] rolesArray = appUserRoles.stream()
+                .map(AppUserRole::getRole)
+                .toArray(String[]::new);
+
+        return rolesArray;
+    }
     public void setAppUserRole(Set<AppUserRole> appUserRole) {
         this.appUserRole = appUserRole;
     }

+ 30 - 0
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/domain/LoginEntity.java

@@ -0,0 +1,30 @@
+package pl.dmcs.jwoszczyk.domain;
+
+public class LoginEntity {
+    String username;
+    String password;
+
+    public LoginEntity(String username, String password) {
+        this.username = username;
+        this.password = password;
+    }
+
+    public LoginEntity() {
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 1 - 0
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/repository/IAppUserRepository.java

@@ -16,6 +16,7 @@ public interface IAppUserRepository extends JpaRepository<AppUser, Long> {
     List<AppUser> findByLastName(String lastName);
     AppUser findById(long id);
     AppUser findByLogin(String login);
+    AppUser findByEmail(String email);
     List<AppUser> findAllByEnabledIsFalse();
 
 }

+ 72 - 0
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/security/JwtTokenUtil.java

@@ -0,0 +1,72 @@
+package pl.dmcs.jwoszczyk.security;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwtBuilder;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import org.springframework.stereotype.Component;
+
+import java.util.Date;
+import java.util.function.Function;
+
+@Component
+public class JwtTokenUtil {
+
+    private static final String SECRET_KEY = "SuperSecureKey2023".repeat(5); // Replace with your own secret key
+    //    private static final long EXPIRATION_TIME = 86400000; // 24 hours in milliseconds
+    private static final long EXPIRATION_TIME = 1000 * 30; // 30 sec
+
+    public static String generateToken(String username, String[] roles) {
+        // Set token expiration time
+        Date expirationDate = new Date(System.currentTimeMillis() + EXPIRATION_TIME);
+
+        // Build the JWT claims
+        Claims claims = Jwts.claims().setSubject(username);
+        claims.put("roles", roles);
+
+        // Build the JWT
+        JwtBuilder jwtBuilder = Jwts.builder()
+                .setClaims(claims)
+                .setIssuedAt(new Date())
+                .setExpiration(expirationDate)
+                .signWith(SignatureAlgorithm.HS256, SECRET_KEY);
+
+        // Generate the token
+        return jwtBuilder.compact();
+    }
+
+    public static boolean validateToken(String token) {
+//        final String username = this.getUsernameFromToken(token);
+//        return (username.equals(user.getUsername()) && !isTokenExpired(token));
+        try {
+            Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    private Boolean isTokenExpired(String token) {
+        final Date expiration = getExpirationDateFromToken(token);
+        return expiration.before(new Date());
+    }
+
+
+    public String getUsernameFromToken(String token) {
+        return getClaimFromToken(token, Claims::getSubject);
+    }
+
+
+    public Date getExpirationDateFromToken(String token) {
+        return getClaimFromToken(token, Claims::getExpiration);
+    }
+
+    public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
+        final Claims claims = getAllClaimsFromToken(token);
+        return claimsResolver.apply(claims);
+    }
+
+    private Claims getAllClaimsFromToken(String token) {
+        return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
+    }
+}

+ 32 - 0
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/security/ValidationErrorResponse.java

@@ -0,0 +1,32 @@
+package pl.dmcs.jwoszczyk.security;
+
+import java.util.List;
+
+public class ValidationErrorResponse {
+    private String message;
+    private List<String> errors;
+
+    public ValidationErrorResponse() {
+    }
+
+    public ValidationErrorResponse(String message, List<String> errors) {
+        this.message = message;
+        this.errors = errors;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public List<String> getErrors() {
+        return errors;
+    }
+
+    public void setErrors(List<String> errors) {
+        this.errors = errors;
+    }
+}

+ 13 - 1
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/service/AppUserService.java

@@ -2,7 +2,6 @@ package pl.dmcs.jwoszczyk.service;
 
 import jakarta.transaction.Transactional;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.stereotype.Service;
 import pl.dmcs.jwoszczyk.domain.AppUser;
@@ -76,4 +75,17 @@ public class AppUserService implements IAppUserService{
         });
     }
 
+    //#############################################################################_Security
+    public boolean isUsernameUnique(String username) {
+        return this.appUserRepository.findByLogin(username) == null;
+    }
+
+    public boolean isEmailUnique(String email) {
+        return this.appUserRepository.findByEmail(email) == null;
+    }
+
+    @Override
+    public void registerUser(AppUser user) {
+        this.appUserRepository.save(user);
+    }
 }

+ 3 - 0
Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/service/IAppUserService.java

@@ -19,6 +19,9 @@ public interface IAppUserService {
 
     //#######################################################_security_related
     AppUser findByLogin(String login);
+    public boolean isUsernameUnique(String username);
+    public boolean isEmailUnique(String email);
+    void registerUser(AppUser user);
 
     //#######################################################_scheduling
     void activateInactiveAppUsers();

BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.class


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/controller/SecurityController.class


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/domain/AppUser.class


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/domain/LoginEntity.class


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/repository/IAppUserRepository.class


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/security/JwtTokenUtil.class


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/security/ValidationErrorResponse.class


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/service/AppUserService.class


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/service/IAppUserService.class


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/lib/jjwt-api-0.11.2.jar


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/lib/jjwt-impl-0.11.2.jar


BIN
Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/lib/jjwt-jackson-0.11.2.jar


BIN
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.class


BIN
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/controller/SecurityController.class


BIN
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/domain/AppUser.class


BIN
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/domain/LoginEntity.class


BIN
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/repository/IAppUserRepository.class


BIN
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/security/JwtTokenUtil.class


BIN
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/security/ValidationErrorResponse.class


BIN
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/service/AppUserService.class


BIN
Backend/Spring/target/classes/pl/dmcs/jwoszczyk/service/IAppUserService.class


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/0.pack


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/10.pack


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/11.pack


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/12.pack


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/13.pack


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/15.pack


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/2.pack


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/8.pack


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/9.pack


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack


BIN
Frontend/RiffMasterFront/.angular/cache/16.0.4/angular-webpack/9163ed2c587ff4665fb17ea4ebc8750a69df1e73/index.pack.old


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/22e6c567cfca28eb7499f46f4707c3c1df18f6792a58a069008129af90af343c.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/32f09522d15475a3c0671946c675aba8c907c1569ddc421aee9e0424e3ef4bf1.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/42bf7d83d8be32482d3377527c339d0d776a5cf597791f7d975c657939b27ffa.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/44d182aa5f83201cd731ad535f3921584d4e0b78b9cac185c0f6fc3b6111b5a2.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/489d688920706c7b7e66f2c4da10a5b535b52e9dc6ce152e352f7d1b409b86b6.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/4ec5d74cc9a5367a0f0134830672622c0c4246925c11f173362eb663f54b04b1.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/57ca0e53e220db86f09f1b327f9123d8491524a93553c95743715ff5564417ba.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/67cd29cb035aeee396e161c6f8722cdbf7d565a5e863508062a76bb7e87b9f2f.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/8e64a916e9ad0b41511e572c0bd1e5f5b10e9bff9e83a281fa856ab15fa2de64.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/92b8c5328812235b1dcf7fa157cbf66e614041571440fa067ecccdbb86e17c35.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/92ec7098907310877ebce08a42cc2842e33bce393123a5e3a71e222a9e54f32a.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/9ba82840f7b232bb2beae4e3a04f2917c1f129e2ce252b1ef656bcb3ac716af3.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/a5b505edf5d8e36ffc5d6453ca1eafb6e5ca9d6ed588f380eadfe57f9e6398c8.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/a69e0865ce26a24232478dbfdd93704f0d6a61040339da0b87adc3e1bd831fde.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/b15a76dbfb86e8779160b5302f1ff11cb2278415f8007a5f8d7c2b14ed3ffb9c.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/b35cdb46a32d5dea2bd82c47ad045e89e99c212361d75c10aaf52666d313ebf6.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/bd230926c726c01c4979dcc29aff8769e8e57d37925c17b2025019b3e0f7a780.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/c6ba7c6da31bd668c3d09b7e81d5d8482b9ce32dec72db1764045cc8d80111d6.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/d8ab847f5d54b54108722462a7edc2fde8bb0b6ab2c4232008759714e3d56828.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/e0d27c666f96fe84e02390b10a23c8b9266de7537ebd326dc3b6443b01cb322c.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/e3e25b63fbcf9714dbc4d2c93eb7b4e833a2e4237bf020dac0b31f502711db05.json


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
Frontend/RiffMasterFront/.angular/cache/16.0.4/babel-webpack/e507b3240d4fdce8578d42bb3d83aa0440517fe86fa55a09fa3f91f6c264be1c.json


+ 32 - 17
Frontend/RiffMasterFront/.idea/workspace.xml

@@ -6,6 +6,20 @@
   <component name="ChangeListManager">
     <list default="true" id="d91bc08d-d968-4797-8fb3-ef602a37db2a" name="Changes" comment="RIFFMASTER: add frontend business logic (riff, song)">
       <change beforePath="$PROJECT_DIR$/../../Backend/Spring/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/.idea/workspace.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/pom.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/pom.xml" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.java" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/configuration/SecurityConfiguration.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/domain/AppUser.java" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/domain/AppUser.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/repository/IAppUserRepository.java" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/repository/IAppUserRepository.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/service/AppUserService.java" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/service/AppUserService.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/service/IAppUserService.java" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/src/main/java/pl/dmcs/jwoszczyk/service/IAppUserService.java" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/domain/AppUser.class" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/domain/AppUser.class" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/repository/IAppUserRepository.class" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/repository/IAppUserRepository.class" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/service/AppUserService.class" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/service/AppUserService.class" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/service/IAppUserService.class" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/target/Spring-1.0-SNAPSHOT/WEB-INF/classes/pl/dmcs/jwoszczyk/service/IAppUserService.class" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/target/classes/pl/dmcs/jwoszczyk/domain/AppUser.class" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/target/classes/pl/dmcs/jwoszczyk/domain/AppUser.class" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/target/classes/pl/dmcs/jwoszczyk/repository/IAppUserRepository.class" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/target/classes/pl/dmcs/jwoszczyk/repository/IAppUserRepository.class" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/target/classes/pl/dmcs/jwoszczyk/service/AppUserService.class" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/target/classes/pl/dmcs/jwoszczyk/service/AppUserService.class" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/../../Backend/Spring/target/classes/pl/dmcs/jwoszczyk/service/IAppUserService.class" beforeDir="false" afterPath="$PROJECT_DIR$/../../Backend/Spring/target/classes/pl/dmcs/jwoszczyk/service/IAppUserService.class" afterDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -27,23 +41,23 @@
     <option name="hideEmptyMiddlePackages" value="true" />
     <option name="showLibraryContents" value="true" />
   </component>
-  <component name="PropertiesComponent">{
-  &quot;keyToString&quot;: {
-    &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
-    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
-    &quot;WebServerToolWindowFactoryState&quot;: &quot;false&quot;,
-    &quot;last_opened_file_path&quot;: &quot;C:/Users/Kuba/Desktop/studia/WPFt/inne/projekt z IWA 2020/front files&quot;,
-    &quot;node.js.detected.package.eslint&quot;: &quot;true&quot;,
-    &quot;node.js.detected.package.tslint&quot;: &quot;true&quot;,
-    &quot;node.js.selected.package.eslint&quot;: &quot;(autodetect)&quot;,
-    &quot;node.js.selected.package.tslint&quot;: &quot;(autodetect)&quot;,
-    &quot;nodejs_interpreter_path&quot;: &quot;node&quot;,
-    &quot;nodejs_package_manager_path&quot;: &quot;npm&quot;,
-    &quot;settings.editor.selected.configurable&quot;: &quot;settings.webpack&quot;,
-    &quot;ts.external.directory.path&quot;: &quot;C:\\Program Files\\JetBrains\\IntelliJ IDEA 2023.1.2\\plugins\\javascript-impl\\jsLanguageServicesImpl\\external&quot;,
-    &quot;vue.rearranger.settings.migration&quot;: &quot;true&quot;
+  <component name="PropertiesComponent"><![CDATA[{
+  "keyToString": {
+    "RunOnceActivity.OpenProjectViewOnStart": "true",
+    "RunOnceActivity.ShowReadmeOnStart": "true",
+    "WebServerToolWindowFactoryState": "false",
+    "last_opened_file_path": "C:/Users/Kuba/Desktop/studia/WPFt/inne/oslo_boating_project-master/oslo_boating_project/boat-reservation-view",
+    "node.js.detected.package.eslint": "true",
+    "node.js.detected.package.tslint": "true",
+    "node.js.selected.package.eslint": "(autodetect)",
+    "node.js.selected.package.tslint": "(autodetect)",
+    "nodejs_interpreter_path": "node",
+    "nodejs_package_manager_path": "npm",
+    "settings.editor.selected.configurable": "settings.webpack",
+    "ts.external.directory.path": "C:\\Program Files\\JetBrains\\IntelliJ IDEA 2023.1.2\\plugins\\javascript-impl\\jsLanguageServicesImpl\\external",
+    "vue.rearranger.settings.migration": "true"
   }
-}</component>
+}]]></component>
   <component name="RecentsManager">
     <key name="CopyFile.RECENT_KEYS">
       <recent name="C:\Users\Quba\Desktop\studia\WPFt\RiffMasterFront\src\app\main" />
@@ -100,7 +114,8 @@
       <workItem from="1686909264196" duration="8471000" />
       <workItem from="1686937499471" duration="1137000" />
       <workItem from="1686989529474" duration="3659000" />
-      <workItem from="1687006518226" duration="869000" />
+      <workItem from="1687006518226" duration="3557000" />
+      <workItem from="1687011087000" duration="1232000" />
     </task>
     <task id="LOCAL-00001" summary="RIFFMASTER: add frontend project">
       <created>1685976235580</created>

+ 7 - 2
Frontend/RiffMasterFront/src/app/main-page/main-page.component.css

@@ -116,7 +116,7 @@ body {
 }
 
 .song-list::-webkit-scrollbar-track {
-  background-color: #f1f1f1;
+  background-color: #555;
 }
 
 .song-list::-webkit-scrollbar-thumb {
@@ -124,5 +124,10 @@ body {
 }
 
 .song-list::-webkit-scrollbar-thumb:hover {
-  background-color: #555;
+  background-color: #999;
+}
+
+button[disabled] {
+  background-color: #888;
+  color: #fff;
 }

+ 1 - 1
Frontend/RiffMasterFront/src/app/main-page/main-page.component.html

@@ -20,7 +20,7 @@
 
       <mat-card-content>
 
-        <mat-form-field appearance="fill">
+        <mat-form-field appearance="fill" >
           <mat-label>Search songs</mat-label>
           <input matInput type="text" placeholder="Search songs" [(ngModel)]="searchQuery">
         </mat-form-field>

+ 3 - 0
Frontend/RiffMasterFront/src/app/main-page/main-page.component.ts

@@ -19,6 +19,7 @@ export class MainPageComponent implements OnInit {
   selectedSong!: Song; // Variable to store the selected song
   inputSong!: Song;
   selectedFileName: string = '';
+  isRemoveButtonDisabled!: boolean;
 
   constructor(
     private datePipe: DatePipe,
@@ -82,6 +83,8 @@ export class MainPageComponent implements OnInit {
       );
     };
     reader.readAsText(this.selectedFile);
+    // Check if a file is selected and update the disabled flag
+    this.isRemoveButtonDisabled = !!this.selectedFile;
   }
 
   upload() {

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác