UserService.java
package com.ctrlbuy.webshop.service;
import com.ctrlbuy.webshop.dto.RegisterRequest;
import com.ctrlbuy.webshop.dto.RegistrationResult;
import com.ctrlbuy.webshop.security.entity.User;
import com.ctrlbuy.webshop.security.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.ArrayList;
import java.util.Optional;
@Service
@RequiredArgsConstructor
@Slf4j
@Transactional
public class UserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
/**
* Registrera ny användare med säker transaktionshantering
*/
@Transactional
public RegistrationResult registerUser(RegisterRequest registerRequest) {
try {
log.info("🚀 Startar registrering för användare: {}", registerRequest.getUsername());
// Validera input
if (registerRequest.getUsername() == null || registerRequest.getUsername().trim().isEmpty()) {
return RegistrationResult.failure("Användarnamn är obligatoriskt");
}
if (registerRequest.getEmail() == null || registerRequest.getEmail().trim().isEmpty()) {
return RegistrationResult.failure("E-post är obligatorisk");
}
if (registerRequest.getPassword() == null || registerRequest.getPassword().length() < 6) {
return RegistrationResult.failure("Lösenord måste vara minst 6 tecken");
}
// Kontrollera om användare redan finns
if (existsByUsernameIncludingInactive(registerRequest.getUsername())) {
return RegistrationResult.failure("Användarnamnet är redan upptaget");
}
if (existsByEmailIncludingInactive(registerRequest.getEmail())) {
return RegistrationResult.failure("E-postadressen är redan registrerad");
}
// Skapa ny användare
User user = new User();
user.setUsername(registerRequest.getUsername().trim());
user.setEmail(registerRequest.getEmail().trim().toLowerCase());
user.setPassword(passwordEncoder.encode(registerRequest.getPassword()));
user.setFirstName(registerRequest.getFirstName() != null ? registerRequest.getFirstName().trim() : "");
user.setLastName(registerRequest.getLastName() != null ? registerRequest.getLastName().trim() : "");
// Sätt rolle - använd USER från User.Role enum
user.setRole(User.Role.USER);
user.setEnabled(true);
user.setEmailVerified(true); // Auto-aktivera för demo
user.setCreatedAt(LocalDateTime.now());
// Spara med transaktion
User savedUser = userRepository.save(user);
log.info("✅ Användare sparad framgångsrikt: ID={}, Username={}", savedUser.getId(), savedUser.getUsername());
return RegistrationResult.success("Registrering lyckades! Du kan nu logga in.");
} catch (Exception e) {
log.error("❌ Fel vid registrering av användare: {}", registerRequest.getUsername(), e);
return RegistrationResult.failure("Ett fel uppstod vid registrering. Försök igen.");
}
}
/**
* Kontrollera om användarnamn finns (inklusive inaktiva användare)
*/
@Transactional(readOnly = true)
public boolean existsByUsernameIncludingInactive(String username) {
if (username == null || username.trim().isEmpty()) {
return true; // Behandla som upptaget för säkerhets skull
}
return userRepository.findByUsername(username.trim()).isPresent();
}
/**
* Kontrollera om e-post finns (inklusive inaktiva användare)
*/
@Transactional(readOnly = true)
public boolean existsByEmailIncludingInactive(String email) {
if (email == null || email.trim().isEmpty()) {
return true; // Behandla som upptaget för säkerhets skull
}
return userRepository.findByEmail(email.trim().toLowerCase()).isPresent();
}
/**
* Hitta användare via användarnamn
*/
@Transactional(readOnly = true)
public Optional<User> findByUsername(String username) {
if (username == null || username.trim().isEmpty()) {
return Optional.empty();
}
return userRepository.findByUsername(username.trim());
}
/**
* Hitta användare via e-post
*/
@Transactional(readOnly = true)
public Optional<User> findByEmail(String email) {
if (email == null || email.trim().isEmpty()) {
return Optional.empty();
}
return userRepository.findByEmail(email.trim().toLowerCase());
}
/**
* Hitta användare via ID
*/
@Transactional(readOnly = true)
public Optional<User> findById(Long id) {
if (id == null) {
return Optional.empty();
}
return userRepository.findById(id);
}
// ===== SAKNADE METODER FÖR CONTROLLERS =====
/**
* Hämta alla användare (för AdminController)
*/
@Transactional(readOnly = true)
public List<User> getAllUsers() {
try {
return userRepository.findAll();
} catch (Exception e) {
log.error("❌ Fel vid hämtning av alla användare", e);
return new ArrayList<>();
}
}
/**
* Spara användare (för AdminVerificationController)
*/
@Transactional
public User save(User user) {
try {
return userRepository.save(user);
} catch (Exception e) {
log.error("❌ Fel vid sparande av användare: {}", user.getUsername(), e);
throw new RuntimeException("Kunde inte spara användare");
}
}
/**
* Verifiera e-post med token (för AuthController)
*/
@Transactional
public boolean verifyEmail(String token) {
try {
// Hitta användare med verifikationstoken
Optional<User> userOpt = userRepository.findAll().stream()
.filter(u -> token.equals(u.getVerificationToken()))
.findFirst();
if (userOpt.isPresent()) {
User user = userOpt.get();
// Kontrollera om token är giltig
if (user.isVerificationTokenValid()) {
user.setEmailVerified(true);
user.setVerificationToken(null);
user.setVerificationTokenExpiry(null);
userRepository.save(user);
log.info("✅ E-post verifierad för användare: {}", user.getUsername());
return true;
}
}
log.warn("⚠️ Ogiltig eller utgången verifikationstoken: {}", token);
return false;
} catch (Exception e) {
log.error("❌ Fel vid e-postverifiering med token: {}", token, e);
return false;
}
}
/**
* Generera återställningstoken (för AuthController)
* Returnerar token som String istället för boolean
*/
@Transactional
public String generateResetToken(String email) {
try {
Optional<User> userOpt = findByEmail(email);
if (userOpt.isPresent()) {
User user = userOpt.get();
// Generera token och sätt giltighetsperiod
String token = java.util.UUID.randomUUID().toString();
user.setResetToken(token);
user.setResetTokenExpiry(LocalDateTime.now().plusHours(24)); // 24 timmar
userRepository.save(user);
log.info("✅ Återställningstoken genererad för: {}", email);
return token; // Returnera token som String
}
log.warn("⚠️ Användare inte funnen för återställningstoken: {}", email);
return null;
} catch (Exception e) {
log.error("❌ Fel vid generering av återställningstoken för: {}", email, e);
return null;
}
}
/**
* Generera återställningstoken med användarnamn och e-post (för PasswordResetController)
* Returnerar token som String istället för boolean
*/
@Transactional
public String generateResetTokenWithUsernameAndEmail(String username, String email) {
try {
// Hitta användare med både användarnamn och e-post
Optional<User> userOpt = userRepository.findAll().stream()
.filter(u -> username.equals(u.getUsername()) && email.equals(u.getEmail()))
.findFirst();
if (userOpt.isPresent()) {
User user = userOpt.get();
String token = java.util.UUID.randomUUID().toString();
user.setResetToken(token);
user.setResetTokenExpiry(LocalDateTime.now().plusHours(24));
userRepository.save(user);
log.info("✅ Återställningstoken genererad för användare: {} ({})", username, email);
return token; // Returnera token som String
}
log.warn("⚠️ Användare inte funnen med användarnamn och e-post: {} / {}", username, email);
return null;
} catch (Exception e) {
log.error("❌ Fel vid generering av återställningstoken för: {} / {}", username, email, e);
return null;
}
}
/**
* Kontrollera om återställningstoken är giltig (för PasswordResetController)
*/
@Transactional(readOnly = true)
public boolean isValidResetToken(String token) {
try {
Optional<User> userOpt = userRepository.findAll().stream()
.filter(u -> token.equals(u.getResetToken()))
.findFirst();
if (userOpt.isPresent()) {
User user = userOpt.get();
boolean isValid = user.isResetTokenValid();
log.debug("🔍 Återställningstoken {} är {}", token, isValid ? "giltig" : "ogiltig");
return isValid;
}
log.warn("⚠️ Återställningstoken inte funnen: {}", token);
return false;
} catch (Exception e) {
log.error("❌ Fel vid kontroll av återställningstoken: {}", token, e);
return false;
}
}
/**
* Återställ lösenord med token (för PasswordResetController)
*/
@Transactional
public boolean resetPassword(String token, String newPassword) {
try {
if (newPassword == null || newPassword.length() < 6) {
log.warn("⚠️ Nytt lösenord för kort vid återställning");
return false;
}
Optional<User> userOpt = userRepository.findAll().stream()
.filter(u -> token.equals(u.getResetToken()))
.findFirst();
if (userOpt.isPresent()) {
User user = userOpt.get();
if (user.isResetTokenValid()) {
// Uppdatera lösenord och rensa token
user.setPassword(passwordEncoder.encode(newPassword));
user.setResetToken(null);
user.setResetTokenExpiry(null);
userRepository.save(user);
log.info("✅ Lösenord återställt för användare: {}", user.getUsername());
return true;
} else {
log.warn("⚠️ Återställningstoken utgången för användare: {}", user.getUsername());
}
} else {
log.warn("⚠️ Ingen användare funnen med återställningstoken: {}", token);
}
return false;
} catch (Exception e) {
log.error("❌ Fel vid återställning av lösenord med token: {}", token, e);
return false;
}
}
}