Initial commit: mail-server with WebFlux backend and Angular v22 Synthwave frontend

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
2026-11-05 01:07:29 +01:00
co-authored by Junie
commit 0339413d6e
78 changed files with 6808 additions and 0 deletions
@@ -0,0 +1,80 @@
package com.mailserver.service;
import com.mailserver.domain.Folder;
import com.mailserver.domain.User;
import com.mailserver.dto.FolderResponse;
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);
user.setCreatedAt(Instant.now());
return userRepository.save(user);
})
.flatMap(user -> {
// Создаём стандартные папки
String[] defaultFolders = {"INBOX", "Sent", "Drafts", "Trash", "Spam"};
return Flux.fromArray(defaultFolders)
.flatMap(name -> {
Folder folder = new Folder();
folder.setUserId(user.getId());
folder.setName(name);
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());
}
public Flux<FolderResponse> getFolders(Long userId) {
return folderRepository.findByUserId(userId)
.map(f -> {
FolderResponse resp = new FolderResponse();
resp.setId(f.getId());
resp.setName(f.getName());
resp.setMessageCount(f.getMessageCount());
resp.setUnreadCount(f.getUnreadCount());
return resp;
});
}
}