diff --git a/backend/src/main/java/de/szut/casino/user/UserController.java b/backend/src/main/java/de/szut/casino/user/UserController.java index 7ee0739..16bdf22 100644 --- a/backend/src/main/java/de/szut/casino/user/UserController.java +++ b/backend/src/main/java/de/szut/casino/user/UserController.java @@ -1,25 +1,55 @@ package de.szut.casino.user; import de.szut.casino.user.dto.CreateUserDto; +import de.szut.casino.user.dto.GetUserDto; import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +@Slf4j @RestController public class UserController { @Autowired private UserService userService; - @GetMapping("/user/{id}") public ResponseEntity getUser(@PathVariable String id) { + if (id == null || !userService.exists(id)) { + return ResponseEntity.notFound().build(); + } return ResponseEntity.ok(userService.getUser(id)); } @PostMapping("/user") public ResponseEntity createUser(@RequestBody @Valid CreateUserDto userData) { + if (userService.exists(userData.getKeycloakId())) { + + return this.redirect("/user/" + userData.getKeycloakId()); + } + return ResponseEntity.ok(userService.createUser(userData)); } + + @GetMapping("/user") + public ResponseEntity getCurrentUser(@RequestHeader("Authorization") String token) { + GetUserDto userData = userService.getCurrentUser(token); + + if (userData == null) { + return ResponseEntity.notFound().build(); + } + + return ResponseEntity.ok(userData); + } + + private ResponseEntity redirect(String route) { + HttpHeaders headers = new HttpHeaders(); + headers.add("Location", route); + + return new ResponseEntity<>(headers, HttpStatus.FOUND); + } } diff --git a/backend/src/main/java/de/szut/casino/user/UserEntity.java b/backend/src/main/java/de/szut/casino/user/UserEntity.java index 3fb45a2..cebd060 100644 --- a/backend/src/main/java/de/szut/casino/user/UserEntity.java +++ b/backend/src/main/java/de/szut/casino/user/UserEntity.java @@ -1,5 +1,6 @@ package de.szut.casino.user; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; @@ -13,6 +14,8 @@ public class UserEntity { @Id @GeneratedValue private Long id; + @Column(unique = true) private String keycloakId; private String username; + private float balance; } diff --git a/backend/src/main/java/de/szut/casino/user/UserMappingService.java b/backend/src/main/java/de/szut/casino/user/UserMappingService.java new file mode 100644 index 0000000..3789a1f --- /dev/null +++ b/backend/src/main/java/de/szut/casino/user/UserMappingService.java @@ -0,0 +1,22 @@ +package de.szut.casino.user; + +import de.szut.casino.user.dto.CreateUserDto; +import de.szut.casino.user.dto.GetUserDto; +import org.springframework.stereotype.Service; + +@Service +public class UserMappingService { + public GetUserDto mapToGetUserDto(UserEntity user) { + return new GetUserDto(user.getKeycloakId(), user.getUsername(), user.getBalance()); + } + + public UserEntity mapToUserEntity(CreateUserDto createUserDto) { + UserEntity user = new UserEntity(); + user.setKeycloakId(createUserDto.getKeycloakId()); + user.setUsername(createUserDto.getUsername()); + user.setBalance(0); + + return user; + } +} + diff --git a/backend/src/main/java/de/szut/casino/user/UserRepository.java b/backend/src/main/java/de/szut/casino/user/UserRepository.java index f009b44..aaa5752 100644 --- a/backend/src/main/java/de/szut/casino/user/UserRepository.java +++ b/backend/src/main/java/de/szut/casino/user/UserRepository.java @@ -8,9 +8,8 @@ import java.util.Optional; @Service public interface UserRepository extends JpaRepository { - boolean existsByUsername(String username); - @Query("SELECT u FROM UserEntity u WHERE u.keycloakId = ?1") Optional findOneByKeycloakId(String keycloakId); + boolean existsByKeycloakId(String keycloakId); } diff --git a/backend/src/main/java/de/szut/casino/user/UserService.java b/backend/src/main/java/de/szut/casino/user/UserService.java index 95cb01a..c3551ad 100644 --- a/backend/src/main/java/de/szut/casino/user/UserService.java +++ b/backend/src/main/java/de/szut/casino/user/UserService.java @@ -2,9 +2,21 @@ package de.szut.casino.user; import de.szut.casino.user.dto.CreateUserDto; import de.szut.casino.user.dto.GetUserDto; +import de.szut.casino.user.dto.KeycloakUserDto; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.web.client.RestTemplate; +import java.net.URI; +import java.net.http.HttpClient; +import org.springframework.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.time.Duration; +import java.util.List; +import java.util.Map; import java.util.Optional; @Service @@ -12,10 +24,14 @@ public class UserService { @Autowired private UserRepository userRepository; + @Autowired + private RestTemplate http; + + @Autowired + private UserMappingService mappingService; + public UserEntity createUser(CreateUserDto createUserDto) { - UserEntity user = new UserEntity(); - user.setUsername(createUserDto.getUsername()); - user.setKeycloakId(createUserDto.getKeycloakId()); + UserEntity user = mappingService.mapToUserEntity(createUserDto); userRepository.save(user); return user; @@ -23,15 +39,31 @@ public class UserService { public GetUserDto getUser(String keycloakId) { Optional user = this.userRepository.findOneByKeycloakId(keycloakId); - if (user.isPresent()) { - System.out.println(user.get()); - GetUserDto getUserDto = new GetUserDto(); - getUserDto.setKeycloakId(user.get().getKeycloakId()); - getUserDto.setUsername(user.get().getUsername()); - return getUserDto; - } - System.out.println("User not found: "+keycloakId); + return user.map(userEntity -> mappingService.mapToGetUserDto(userEntity)).orElse(null); - return null; + } + + public GetUserDto getCurrentUser(String token) { + KeycloakUserDto userData = getKeycloakUserInfo(token); + + if (userData == null) { + return null; + } + Optional user = this.userRepository.findOneByKeycloakId(userData.getSub()); + + return user.map(userEntity -> mappingService.mapToGetUserDto(userEntity)).orElse(null); + + } + + private KeycloakUserDto getKeycloakUserInfo(String token) { + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", token); + ResponseEntity response = this.http.exchange("http://localhost:9090/realms/LF12/protocol/openid-connect/userinfo", HttpMethod.GET, new HttpEntity<>(headers), KeycloakUserDto.class); + + return response.getBody(); + } + + public boolean exists(String keycloakId) { + return userRepository.existsByKeycloakId(keycloakId); } } diff --git a/backend/src/main/java/de/szut/casino/user/dto/GetUserDto.java b/backend/src/main/java/de/szut/casino/user/dto/GetUserDto.java index 95855f1..fb690af 100644 --- a/backend/src/main/java/de/szut/casino/user/dto/GetUserDto.java +++ b/backend/src/main/java/de/szut/casino/user/dto/GetUserDto.java @@ -12,4 +12,5 @@ import lombok.Setter; public class GetUserDto { private String keycloakId; private String username; + private float balance; } diff --git a/backend/src/main/java/de/szut/casino/user/dto/KeycloakUserDto.java b/backend/src/main/java/de/szut/casino/user/dto/KeycloakUserDto.java new file mode 100644 index 0000000..4238e13 --- /dev/null +++ b/backend/src/main/java/de/szut/casino/user/dto/KeycloakUserDto.java @@ -0,0 +1,15 @@ +package de.szut.casino.user.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class KeycloakUserDto { + private String sub; + private String preferred_username; +} diff --git a/frontend/src/app/login-success/login-success.component.ts b/frontend/src/app/login-success/login-success.component.ts index 5da8136..fea0072 100644 --- a/frontend/src/app/login-success/login-success.component.ts +++ b/frontend/src/app/login-success/login-success.component.ts @@ -1,4 +1,4 @@ -import { Component, inject, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core'; import { UserService } from '../service/user.service'; import { KeycloakService } from 'keycloak-angular'; import { Router } from '@angular/router'; @@ -8,7 +8,8 @@ import { Router } from '@angular/router'; standalone: true, imports: [], templateUrl: './login-success.component.html', - styleUrl: './login-success.component.css' + styleUrl: './login-success.component.css', + changeDetection: ChangeDetectionStrategy.OnPush, }) export class LoginSuccessComponent implements OnInit{ private userService: UserService = inject(UserService); @@ -17,7 +18,7 @@ export class LoginSuccessComponent implements OnInit{ async ngOnInit() { const userProfile = await this.keycloakService.loadUserProfile(); - const user = this.userService.getCurrentUser(userProfile); + const user = await this.userService.getOrCreateUser(userProfile); sessionStorage.setItem('user', JSON.stringify(user)); // this.router.navigate(['']); diff --git a/frontend/src/app/model/User.ts b/frontend/src/app/model/User.ts new file mode 100644 index 0000000..28081e4 --- /dev/null +++ b/frontend/src/app/model/User.ts @@ -0,0 +1,4 @@ +export interface User { + keycloakId: string; + username: string; +} diff --git a/frontend/src/app/service/user.service.ts b/frontend/src/app/service/user.service.ts index a195238..00bafe1 100644 --- a/frontend/src/app/service/user.service.ts +++ b/frontend/src/app/service/user.service.ts @@ -1,7 +1,8 @@ import { inject, Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { KeycloakProfile } from 'keycloak-js'; -import { async } from 'rxjs'; +import { async, Observable } from 'rxjs'; +import { User } from '../model/User'; @Injectable({ providedIn: 'root', @@ -9,18 +10,18 @@ import { async } from 'rxjs'; export class UserService { private http: HttpClient = inject(HttpClient); - public getUser(id: string) { - return this.http.get<{ keycloakId: string, username: string } | null>(`/backend/user/${id}`); + public getUser(id: string): Observable { + return this.http.get(`/backend/user/${id}`); } - public createUser(id: string, username: string) { - return this.http.post<{ keycloakId: string, username: string }>('/backend/user', { + public createUser(id: string, username: string): Observable { + return this.http.post('/backend/user', { keycloakId: id, username: username, }); } - public async getCurrentUser(userProfile: KeycloakProfile) { + public async getOrCreateUser(userProfile: KeycloakProfile) { if (userProfile.id == null) { return; }