Files
reactive-mail-server/backend/src/main/java/com/mailserver/service/UserService.java
T
Liosha84 29b1beabe0 Почтовый кабинет: регистрация, папки, черновики, вложения, грид @jambotron/aria-grid, интерфейс по synthwave-шаблону
Бэкенд: регистрация со входом сразу и /api/config, профиль и смена пароля, свои папки, PATCH письма
(прочитано, флажок, перенос; Спам ставит отметку), корзина и очистка, черновики, несколько адресатов и копия,
вложения черновика уходят с письмом, вложения и заголовки To/Cc входящих сохраняются, письма заблокированных —
в Спам. Исправлено: загрузка файла (415), колонка content_id (500 на любых вложениях), SPA-маршрут с точкой.
Фронтенд переписан: все таблицы — грид, оформление — шаблон synthwave-design-showcase.html.

α
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 16:41:29 +01:00

82 lines
3.4 KiB
Java

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<User> 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<User> 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<Void> 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();
}
public Mono<User> updateDisplayName(User user, String displayName) {
user.setDisplayName(displayName.trim());
return userRepository.save(user);
}
}