Public Access
Added lots of new stuff
- extended the jwt and put userid into it - completed update settings - added settings also in me call
This commit is contained in:
1 parent
d498ef8827
commit
e21dea1e18
24 files changed
+271
-30
No files matched your search
@@ -0,0 +1,10 @@
|
|||||||
|
package auth_service.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableAsync;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableAsync
|
||||||
|
public class AsyncConfig {
|
||||||
|
// This class enables Spring's @Async annotation functionality globally
|
||||||
|
}
|
||||||
@@ -45,10 +45,13 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
final String userEmail = jwtService.extractEmail(jwt);
|
final String userEmail = jwtService.extractEmail(jwt);
|
||||||
|
final String userId = jwtService.extractUserId(jwt);
|
||||||
|
|
||||||
if (userEmail != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
if (userEmail != null && userId != null && SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||||
|
|
||||||
|
UserPrincipal principal = new UserPrincipal(userId, userEmail);
|
||||||
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
|
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
|
||||||
userEmail,
|
principal,
|
||||||
null,
|
null,
|
||||||
Collections.emptyList()
|
Collections.emptyList()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -28,9 +28,10 @@ public class JwtService {
|
|||||||
*
|
*
|
||||||
* @return A signed JWT string
|
* @return A signed JWT string
|
||||||
*/
|
*/
|
||||||
public String generateToken(String email) {
|
public String generateToken(String userId, String email) {
|
||||||
return Jwts.builder()
|
return Jwts.builder()
|
||||||
.subject(email)
|
.subject(email)
|
||||||
|
.claim("userId", userId)
|
||||||
.issuedAt(new Date(System.currentTimeMillis()))
|
.issuedAt(new Date(System.currentTimeMillis()))
|
||||||
.expiration(new Date(System.currentTimeMillis() + JWT_EXPIRATION_MS))
|
.expiration(new Date(System.currentTimeMillis() + JWT_EXPIRATION_MS))
|
||||||
.signWith(getSigningKey())
|
.signWith(getSigningKey())
|
||||||
@@ -46,6 +47,15 @@ public class JwtService {
|
|||||||
.getSubject();
|
.getSubject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String extractUserId(String token) {
|
||||||
|
return Jwts.parser()
|
||||||
|
.verifyWith(getSigningKey())
|
||||||
|
.build()
|
||||||
|
.parseSignedClaims(token)
|
||||||
|
.getPayload()
|
||||||
|
.get("userId", String.class);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isTokenValid(String token) {
|
public boolean isTokenValid(String token) {
|
||||||
try {
|
try {
|
||||||
Jwts.parser()
|
Jwts.parser()
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package auth_service.configuration.security;
|
||||||
|
|
||||||
|
import java.security.Principal;
|
||||||
|
|
||||||
|
public record UserPrincipal(
|
||||||
|
String id,
|
||||||
|
String email
|
||||||
|
) implements Principal {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getIdAsLong() {
|
||||||
|
return Long.parseLong(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,8 +36,7 @@ public class LoginController {
|
|||||||
|
|
||||||
var user = ApiMapper.toModel(request);
|
var user = ApiMapper.toModel(request);
|
||||||
var authenticatedUser = loginService.login(user);
|
var authenticatedUser = loginService.login(user);
|
||||||
var token = jwtService.generateToken(authenticatedUser.getEmail());
|
var token = jwtService.generateToken(authenticatedUser.getId() + "", authenticatedUser.getEmail());
|
||||||
|
|
||||||
return ResponseEntity.ok(new LoginResponse("Login successful", token));
|
return ResponseEntity.ok(new LoginResponse("Login successful", token));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
package auth_service.domain.user.controller;
|
package auth_service.domain.user.controller;
|
||||||
|
|
||||||
|
import auth_service.configuration.security.UserPrincipal;
|
||||||
|
import auth_service.domain.user.controller.dto.request.UserSettingsRequest;
|
||||||
import auth_service.domain.user.controller.dto.response.UserProfileResponse;
|
import auth_service.domain.user.controller.dto.response.UserProfileResponse;
|
||||||
import auth_service.domain.user.controller.mapper.ApiMapper;
|
import auth_service.domain.user.controller.mapper.ApiMapper;
|
||||||
import auth_service.domain.user.service.UserService;
|
import auth_service.domain.user.service.UserService;
|
||||||
import io.micrometer.core.annotation.Timed;
|
import io.micrometer.core.annotation.Timed;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
|
||||||
|
|
||||||
import java.security.Principal;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller handling user profile operations for the dashboard.
|
* Controller handling user profile operations for the dashboard.
|
||||||
@@ -28,11 +27,19 @@ public class UserController {
|
|||||||
*/
|
*/
|
||||||
@GetMapping(value = "/me", version = "1.0", produces = "application/json")
|
@GetMapping(value = "/me", version = "1.0", produces = "application/json")
|
||||||
@Timed(value = "user.me.v1.requests.time", description = "Time taken to process v1 user profile requests")
|
@Timed(value = "user.me.v1.requests.time", description = "Time taken to process v1 user profile requests")
|
||||||
public ResponseEntity<UserProfileResponse> getCurrentUserV1(Principal principal) {
|
public ResponseEntity<UserProfileResponse> getCurrentUserV1(@AuthenticationPrincipal UserPrincipal principal) {
|
||||||
|
|
||||||
// this is the email from the login, if a user is not authenticated, it will not even come to this point.
|
// this is the email from the login, if a user is not authenticated, it will not even come to this point.
|
||||||
var authenticatedEmail = principal.getName();
|
var authenticatedEmail = principal.email();
|
||||||
var profileResponse = this.userService.getUserByEmail(authenticatedEmail);
|
var profileResponse = this.userService.getUserByEmail(authenticatedEmail);
|
||||||
return ResponseEntity.ok(ApiMapper.toApi(profileResponse));
|
return ResponseEntity.ok(ApiMapper.toApi(profileResponse));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PutMapping(value = "/settings", version = "1.0", produces = "application/json")
|
||||||
|
@Timed(value = "user.me.v1.requests.time", description = "Time taken to process v1 user profile requests")
|
||||||
|
public ResponseEntity<Void> updateUserSettings(@AuthenticationPrincipal UserPrincipal principal,
|
||||||
|
@RequestBody UserSettingsRequest request) {
|
||||||
|
this.userService.updateUserSettings(principal.getIdAsLong(), request.steamId(), ApiMapper.toDomain(request));
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
package auth_service.domain.user.controller.dto.request;
|
||||||
|
|
||||||
|
public record UserSettingsRequest(boolean useDarkTheme, String language, long steamId) {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package auth_service.domain.user.controller.dto.response;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
public record SettingsResponse(long id, boolean useDarkTheme, String language) {
|
||||||
|
}
|
||||||
+1
-1
@@ -5,5 +5,5 @@ import lombok.Builder;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
public record UserProfileResponse(long id, String email, String role, LocalDateTime lastLogin, LocalDateTime createdDate, long steamId) {
|
public record UserProfileResponse(long id, String email, String role, LocalDateTime lastLogin, LocalDateTime createdDate, long steamId, SettingsResponse settings) {
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
package auth_service.domain.user.controller.mapper;
|
package auth_service.domain.user.controller.mapper;
|
||||||
|
|
||||||
|
|
||||||
|
import auth_service.domain.user.controller.dto.request.UserSettingsRequest;
|
||||||
|
import auth_service.domain.user.controller.dto.response.SettingsResponse;
|
||||||
import auth_service.domain.user.controller.dto.response.UserProfileResponse;
|
import auth_service.domain.user.controller.dto.response.UserProfileResponse;
|
||||||
import auth_service.domain.user.model.User;
|
import auth_service.domain.user.model.User;
|
||||||
|
import auth_service.domain.user.model.UserSettings;
|
||||||
|
|
||||||
public abstract class ApiMapper {
|
public abstract class ApiMapper {
|
||||||
private ApiMapper() {
|
private ApiMapper() {
|
||||||
@@ -15,6 +18,20 @@ public abstract class ApiMapper {
|
|||||||
.createdDate(user.getCreatedDate())
|
.createdDate(user.getCreatedDate())
|
||||||
.lastLogin(user.getLastLogin())
|
.lastLogin(user.getLastLogin())
|
||||||
.steamId(user.getSteamId())
|
.steamId(user.getSteamId())
|
||||||
.role("USER").build();
|
.role("USER")
|
||||||
|
.settings(SettingsResponse.builder()
|
||||||
|
.id(user.getId())
|
||||||
|
.useDarkTheme(user.getSettings().getTheme().equals("dark"))
|
||||||
|
.language(user.getSettings().getLanguage())
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UserSettings toDomain(UserSettingsRequest request) {
|
||||||
|
return UserSettings.builder()
|
||||||
|
.theme(request.useDarkTheme() ? "dark" : "light")
|
||||||
|
.language(request.language())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,4 +14,6 @@ public class User {
|
|||||||
private LocalDateTime lastLogin;
|
private LocalDateTime lastLogin;
|
||||||
private LocalDateTime createdDate;
|
private LocalDateTime createdDate;
|
||||||
private long steamId;
|
private long steamId;
|
||||||
|
|
||||||
|
private UserSettings settings;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package auth_service.domain.user.model;
|
||||||
|
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public class UserSettings {
|
||||||
|
private String language;
|
||||||
|
private String theme;
|
||||||
|
}
|
||||||
@@ -2,6 +2,9 @@ package auth_service.domain.user.persistence;
|
|||||||
|
|
||||||
|
|
||||||
import auth_service.domain.user.model.User;
|
import auth_service.domain.user.model.User;
|
||||||
|
import auth_service.domain.user.model.UserSettings;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@@ -16,4 +19,10 @@ public interface UserRepository {
|
|||||||
* @return An Optional containing the user if found
|
* @return An Optional containing the user if found
|
||||||
*/
|
*/
|
||||||
Optional<User> findByEmail(String email);
|
Optional<User> findByEmail(String email);
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
UserSettings findSettingsByUserId(String userId);
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
boolean updateSettings(long userId, long steamId, UserSettings settings);
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,19 @@
|
|||||||
package auth_service.domain.user.persistence;
|
package auth_service.domain.user.persistence;
|
||||||
|
|
||||||
import auth_service.domain.user.model.User;
|
import auth_service.domain.user.model.User;
|
||||||
|
import auth_service.domain.user.model.UserSettings;
|
||||||
import auth_service.domain.user.persistence.entities.UserEntity;
|
import auth_service.domain.user.persistence.entities.UserEntity;
|
||||||
|
import auth_service.domain.user.persistence.entities.UserSettingsEntity;
|
||||||
import auth_service.domain.user.persistence.mapper.EntityMapper;
|
import auth_service.domain.user.persistence.mapper.EntityMapper;
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import jakarta.persistence.PersistenceContext;
|
import jakarta.persistence.PersistenceContext;
|
||||||
import jakarta.persistence.TypedQuery;
|
import jakarta.persistence.TypedQuery;
|
||||||
|
import jakarta.transaction.Transactional;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public class UserRepositoryImpl implements UserRepository {
|
public class UserRepositoryImpl implements UserRepository {
|
||||||
@@ -21,7 +26,11 @@ public class UserRepositoryImpl implements UserRepository {
|
|||||||
var userEntityCriteriaQuery = criteriaBuilder.createQuery(UserEntity.class);
|
var userEntityCriteriaQuery = criteriaBuilder.createQuery(UserEntity.class);
|
||||||
var userEntity = userEntityCriteriaQuery.from(UserEntity.class);
|
var userEntity = userEntityCriteriaQuery.from(UserEntity.class);
|
||||||
|
|
||||||
// Build the query: SELECT u FROM UserEntity u WHERE u.email = :email
|
// Fetch the settings eagerly using a LEFT JOIN to prevent N+1 queries.
|
||||||
|
// A LEFT JOIN ensures the user is returned even if no settings exist yet.
|
||||||
|
userEntity.fetch("settings", jakarta.persistence.criteria.JoinType.LEFT);
|
||||||
|
|
||||||
|
// Build the query: SELECT u FROM UserEntity u LEFT JOIN FETCH u.settings WHERE u.email = :email
|
||||||
userEntityCriteriaQuery.select(userEntity).where(criteriaBuilder.equal(userEntity.get("email"), email));
|
userEntityCriteriaQuery.select(userEntity).where(criteriaBuilder.equal(userEntity.get("email"), email));
|
||||||
|
|
||||||
TypedQuery<UserEntity> typedQuery = entityManager.createQuery(userEntityCriteriaQuery);
|
TypedQuery<UserEntity> typedQuery = entityManager.createQuery(userEntityCriteriaQuery);
|
||||||
@@ -30,4 +39,37 @@ public class UserRepositoryImpl implements UserRepository {
|
|||||||
.findFirst()
|
.findFirst()
|
||||||
.map(EntityMapper::mapToModel);
|
.map(EntityMapper::mapToModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull UserSettings findSettingsByUserId(String userId) {
|
||||||
|
UserSettingsEntity entity = entityManager.find(UserSettingsEntity.class, UUID.fromString(userId));
|
||||||
|
|
||||||
|
if (entity == null) {
|
||||||
|
// Return defaults if none exist yet
|
||||||
|
return UserSettings.builder()
|
||||||
|
.language("")
|
||||||
|
.theme("light")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
return UserSettings.builder()
|
||||||
|
.language(entity.getLanguage())
|
||||||
|
.theme(entity.getTheme())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
@Override
|
||||||
|
public boolean updateSettings(long userId, long steamId, UserSettings settings) {
|
||||||
|
var entity = EntityMapper.toPersistence(userId, settings);
|
||||||
|
// merge() acts as an upsert: it updates if the ID exists, or inserts if it doesn't.
|
||||||
|
entityManager.merge(entity);
|
||||||
|
|
||||||
|
var userEntity = entityManager.find(UserEntity.class, userId);
|
||||||
|
if (userEntity != null && userEntity.getSteamId() != steamId) {
|
||||||
|
userEntity.setSteamId(steamId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -38,4 +38,8 @@ public class UserEntity {
|
|||||||
|
|
||||||
@Column(name = "last_login_date")
|
@Column(name = "last_login_date")
|
||||||
private LocalDateTime lastLoginDate;
|
private LocalDateTime lastLoginDate;
|
||||||
|
|
||||||
|
@OneToOne(cascade = jakarta.persistence.CascadeType.ALL, fetch = jakarta.persistence.FetchType.LAZY)
|
||||||
|
@jakarta.persistence.PrimaryKeyJoinColumn
|
||||||
|
private UserSettingsEntity settings;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package auth_service.domain.user.persistence.entities;
|
||||||
|
|
||||||
|
import jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "user_settings")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class UserSettingsEntity {
|
||||||
|
|
||||||
|
// No @GeneratedValue! The ID is strictly the user_id from the users table.
|
||||||
|
@Id
|
||||||
|
@Column(name = "user_id")
|
||||||
|
private long userId;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String language;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String theme;
|
||||||
|
}
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
package auth_service.domain.user.persistence.mapper;
|
package auth_service.domain.user.persistence.mapper;
|
||||||
|
|
||||||
import auth_service.domain.user.model.User;
|
import auth_service.domain.user.model.User;
|
||||||
|
import auth_service.domain.user.model.UserSettings;
|
||||||
import auth_service.domain.user.persistence.entities.UserEntity;
|
import auth_service.domain.user.persistence.entities.UserEntity;
|
||||||
|
import auth_service.domain.user.persistence.entities.UserSettingsEntity;
|
||||||
|
|
||||||
public abstract class EntityMapper {
|
public abstract class EntityMapper {
|
||||||
|
|
||||||
@@ -9,17 +11,42 @@ public abstract class EntityMapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static User mapToModel(UserEntity entity) {
|
public static User mapToModel(UserEntity entity) {
|
||||||
User model = User.builder().build();
|
if (entity == null) {
|
||||||
|
return null;
|
||||||
if (entity != null) {
|
|
||||||
model.setId(entity.getId());
|
|
||||||
model.setEmail(entity.getEmail());
|
|
||||||
model.setEncryptedPassword(entity.getPassword());
|
|
||||||
model.setLastLogin(entity.getLastLoginDate());
|
|
||||||
model.setCreatedDate(entity.getRegistrationDate());
|
|
||||||
model.setSteamId(entity.getSteamId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return model;
|
// 1. Map the settings if they exist, otherwise use defaults
|
||||||
|
UserSettings settingsModel;
|
||||||
|
if (entity.getSettings() != null) {
|
||||||
|
settingsModel = UserSettings.builder()
|
||||||
|
.language(entity.getSettings().getLanguage())
|
||||||
|
.theme(entity.getSettings().getTheme())
|
||||||
|
.build();
|
||||||
|
} else {
|
||||||
|
// Fallback default settings for users without an entry in the database
|
||||||
|
settingsModel = UserSettings.builder()
|
||||||
|
.language("en")
|
||||||
|
.theme("system")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Map the main user fields and attach the settings
|
||||||
|
return User.builder()
|
||||||
|
.id(entity.getId())
|
||||||
|
.email(entity.getEmail())
|
||||||
|
.encryptedPassword(entity.getPassword())
|
||||||
|
.lastLogin(entity.getLastLoginDate())
|
||||||
|
.createdDate(entity.getRegistrationDate())
|
||||||
|
.steamId(entity.getSteamId())
|
||||||
|
.settings(settingsModel)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserSettingsEntity toPersistence(long userId, UserSettings settings) {
|
||||||
|
UserSettingsEntity entity = new UserSettingsEntity();
|
||||||
|
entity.setUserId(userId);
|
||||||
|
entity.setLanguage(settings.getLanguage());
|
||||||
|
entity.setTheme(settings.getTheme());
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,11 +2,16 @@ package auth_service.domain.user.service;
|
|||||||
|
|
||||||
import auth_service.domain.user.exception.UserNotFoundException;
|
import auth_service.domain.user.exception.UserNotFoundException;
|
||||||
import auth_service.domain.user.model.User;
|
import auth_service.domain.user.model.User;
|
||||||
|
import auth_service.domain.user.model.UserSettings;
|
||||||
import auth_service.domain.user.persistence.UserRepository;
|
import auth_service.domain.user.persistence.UserRepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.cache.annotation.Cacheable;
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class UserService {
|
public class UserService {
|
||||||
@@ -23,4 +28,14 @@ public class UserService {
|
|||||||
public User getUserByEmail(String email) {
|
public User getUserByEmail(String email) {
|
||||||
return userRepository.findByEmail(email).orElseThrow(() -> new UserNotFoundException("Could not find user with email " + email));
|
return userRepository.findByEmail(email).orElseThrow(() -> new UserNotFoundException("Could not find user with email " + email));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Async
|
||||||
|
@Transactional
|
||||||
|
public void updateUserSettings(long userId, long steamId, UserSettings userSettings) {
|
||||||
|
var updated = userRepository.updateSettings(userId, steamId, userSettings);
|
||||||
|
if (updated) {
|
||||||
|
log.info("Steam id has changed!");
|
||||||
|
}
|
||||||
|
log.info("User settings has been updated!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
File renamed without changes.
@@ -15,6 +15,9 @@ spring:
|
|||||||
baseline-on-migrate: true
|
baseline-on-migrate: true
|
||||||
# Explicitly state where to look for scripts
|
# Explicitly state where to look for scripts
|
||||||
locations: classpath:db/migration
|
locations: classpath:db/migration
|
||||||
|
threads:
|
||||||
|
virtual:
|
||||||
|
enabled: true
|
||||||
mvc:
|
mvc:
|
||||||
apiversion:
|
apiversion:
|
||||||
use:
|
use:
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
-- Create the users table
|
-- Create the users table
|
||||||
ALTER TABLE users
|
ALTER TABLE users
|
||||||
ADD COLUMN steam_id BIGINT,
|
ADD COLUMN steam_id BIGINT DEFAULT 0,
|
||||||
ADD COLUMN registration_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
ADD COLUMN registration_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
ADD COLUMN last_login_date TIMESTAMP;
|
ADD COLUMN last_login_date TIMESTAMP;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
CREATE TABLE user_settings
|
||||||
|
(
|
||||||
|
user_id BIGSERIAL PRIMARY KEY REFERENCES users (id) ON DELETE CASCADE,
|
||||||
|
language VARCHAR(10) NOT NULL DEFAULT '',
|
||||||
|
theme VARCHAR(20) NOT NULL DEFAULT 'light'
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO user_settings (user_id, language, theme)
|
||||||
|
SELECT id, '', 'light'
|
||||||
|
FROM users;
|
||||||
@@ -29,10 +29,11 @@ class JwtServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
void generateToken_Success() {
|
void generateToken_Success() {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
var userId = "0815";
|
||||||
var email = "test@example.com";
|
var email = "test@example.com";
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var token = jwtService.generateToken(email);
|
var token = jwtService.generateToken(userId, email);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
assertNotNull(token);
|
assertNotNull(token);
|
||||||
@@ -42,8 +43,9 @@ class JwtServiceTest {
|
|||||||
@Test
|
@Test
|
||||||
void extractEmail_Success() {
|
void extractEmail_Success() {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
var userId = "0815";
|
||||||
var email = "test@example.com";
|
var email = "test@example.com";
|
||||||
var token = jwtService.generateToken(email);
|
var token = jwtService.generateToken(userId, email);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var extractedEmail = jwtService.extractEmail(token);
|
var extractedEmail = jwtService.extractEmail(token);
|
||||||
@@ -52,11 +54,26 @@ class JwtServiceTest {
|
|||||||
assertEquals(email, extractedEmail);
|
assertEquals(email, extractedEmail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void extractUserId_Success() {
|
||||||
|
// Arrange
|
||||||
|
var userId = "0815";
|
||||||
|
var email = "test@example.com";
|
||||||
|
var token = jwtService.generateToken(userId, email);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var extractedUserId = jwtService.extractUserId(token);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertEquals(userId, extractedUserId);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void isTokenValid_Success() {
|
void isTokenValid_Success() {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
var userId = "0815";
|
||||||
var email = "test@example.com";
|
var email = "test@example.com";
|
||||||
var token = jwtService.generateToken(email);
|
var token = jwtService.generateToken(userId, email);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var isValid = jwtService.isTokenValid(token);
|
var isValid = jwtService.isTokenValid(token);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class LoginControllerTest {
|
|||||||
var request = new LoginRequest("test@example.com", "password");
|
var request = new LoginRequest("test@example.com", "password");
|
||||||
var authenticatedUser = User.builder().email("test@example.com").build();
|
var authenticatedUser = User.builder().email("test@example.com").build();
|
||||||
when(loginService.login(any(User.class))).thenReturn(authenticatedUser);
|
when(loginService.login(any(User.class))).thenReturn(authenticatedUser);
|
||||||
when(jwtService.generateToken("test@example.com")).thenReturn("mock-token");
|
when(jwtService.generateToken("0815", "test@example.com")).thenReturn("mock-token");
|
||||||
|
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
mockMvc.perform(post("/api/auth/login")
|
mockMvc.perform(post("/api/auth/login")
|
||||||
|
|||||||
Reference in new issue
Block a user