package com.mailserver.service; import com.mailserver.domain.Folder; import com.mailserver.domain.User; import com.mailserver.repository.FolderRepository; import com.mailserver.repository.UserRepository; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.Instant; @Service public class UserService { private final UserRepository userRepository; private final FolderRepository folderRepository; private final BCryptPasswordEncoder passwordEncoder; public UserService(UserRepository userRepository, FolderRepository folderRepository) { this.userRepository = userRepository; this.folderRepository = folderRepository; this.passwordEncoder = new BCryptPasswordEncoder(); } public Mono register(String email, String password, String displayName) { return userRepository.existsByEmail(email) .flatMap(exists -> { if (exists) { return Mono.error(new IllegalArgumentException("Email already registered: " + email)); } User user = new User(); user.setEmail(email); user.setPassword(passwordEncoder.encode(password)); user.setDisplayName(displayName == null || displayName.isBlank() ? email.substring(0, email.indexOf('@')) : displayName.trim()); user.setCreatedAt(Instant.now()); return userRepository.save(user); }) .flatMap(user -> { // Создаём стандартные папки return Flux.fromIterable(MailService.SYSTEM_FOLDERS) .concatMap(name -> { Folder folder = new Folder(); folder.setUserId(user.getId()); folder.setName(name); folder.setSystem(true); folder.setCreatedAt(Instant.now()); return folderRepository.save(folder); }) .then(Mono.just(user)); }); } public Mono findByEmail(String email) { return userRepository.findByEmail(email) .switchIfEmpty(Mono.error(new IllegalArgumentException("User not found: " + email))); } /** * Проверяет, совпадает ли пароль с хэшем, хранящимся у пользователя. */ public boolean checkPassword(User user, String rawPassword) { return passwordEncoder.matches(rawPassword, user.getPassword()); } /** New password, only with the current one. */ public Mono changePassword(User user, String currentPassword, String newPassword) { if (!checkPassword(user, currentPassword)) { return Mono.error(MailService.badRequest("Current password is wrong")); } user.setPassword(passwordEncoder.encode(newPassword)); return userRepository.save(user).then(); } /** The mailbox, or empty (no error). */ public Mono findOptional(String email) { return userRepository.findByEmail(email.toLowerCase(java.util.Locale.ROOT)); } public Flux all() { return userRepository.findAll(); } public Mono byId(Long id) { return userRepository.findById(id); } /** Administrator sets a new password (Settings → Mailboxes): no current password needed. */ public Mono setPassword(User user, String newPassword) { user.setPassword(passwordEncoder.encode(newPassword)); return userRepository.save(user); } public Mono setActive(User user, boolean active) { user.setActive(active); return userRepository.save(user); } public Mono setTrap(User user, boolean trap) { user.setTrap(trap); return userRepository.save(user); } public Mono updateDisplayName(User user, String displayName) { user.setDisplayName(displayName.trim()); return userRepository.save(user); } }