package com.openisle.service; import com.openisle.model.User; import com.openisle.model.Role; import com.openisle.service.PasswordValidator; import com.openisle.service.UsernameValidator; import com.openisle.service.AvatarGenerator; import com.openisle.exception.FieldException; import com.openisle.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.Optional; import java.util.Random; @Service @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; private final PasswordValidator passwordValidator; private final UsernameValidator usernameValidator; private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); private final ImageUploader imageUploader; private final AvatarGenerator avatarGenerator; public User register(String username, String email, String password, String reason, com.openisle.model.RegisterMode mode) { usernameValidator.validate(username); passwordValidator.validate(password); // ── 先按用户名查 ────────────────────────────────────────── Optional byUsername = userRepository.findByUsername(username); if (byUsername.isPresent()) { User u = byUsername.get(); if (u.isVerified()) { // 已验证 → 直接拒绝 throw new FieldException("username", "User name already exists"); } // 未验证 → 允许“重注册”:覆盖必要字段并重新发验证码 u.setEmail(email); // 若不允许改邮箱可去掉 u.setPassword(passwordEncoder.encode(password)); u.setVerificationCode(genCode()); u.setRegisterReason(reason); u.setApproved(mode == com.openisle.model.RegisterMode.DIRECT); return userRepository.save(u); } // ── 再按邮箱查 ─────────────────────────────────────────── Optional byEmail = userRepository.findByEmail(email); if (byEmail.isPresent()) { User u = byEmail.get(); if (u.isVerified()) { // 已验证 → 直接拒绝 throw new FieldException("email", "User email already exists"); } // 未验证 → 允许“重注册” u.setUsername(username); // 若不允许改用户名可去掉 u.setPassword(passwordEncoder.encode(password)); u.setVerificationCode(genCode()); u.setRegisterReason(reason); u.setApproved(mode == com.openisle.model.RegisterMode.DIRECT); return userRepository.save(u); } // ── 完全新用户 ─────────────────────────────────────────── User user = new User(); user.setUsername(username); user.setEmail(email); user.setPassword(passwordEncoder.encode(password)); user.setRole(Role.USER); user.setVerified(false); user.setVerificationCode(genCode()); user.setAvatar(avatarGenerator.generate(username)); user.setRegisterReason(reason); user.setApproved(mode == com.openisle.model.RegisterMode.DIRECT); return userRepository.save(user); } public User registerWithInvite(String username, String email, String password) { User user = register(username, email, password, "", com.openisle.model.RegisterMode.DIRECT); user.setVerified(true); user.setVerificationCode(genCode()); return userRepository.save(user); } private String genCode() { return String.format("%06d", new Random().nextInt(1000000)); } public boolean verifyCode(String username, String code) { Optional userOpt = userRepository.findByUsername(username); if (userOpt.isPresent() && code.equals(userOpt.get().getVerificationCode())) { User user = userOpt.get(); user.setVerified(true); user.setVerificationCode(null); userRepository.save(user); return true; } return false; } public Optional authenticate(String username, String password) { return userRepository.findByUsername(username) .filter(User::isVerified) .filter(User::isApproved) .filter(user -> passwordEncoder.matches(password, user.getPassword())); } public boolean matchesPassword(User user, String rawPassword) { return passwordEncoder.matches(rawPassword, user.getPassword()); } public Optional findByUsername(String username) { return userRepository.findByUsername(username); } public Optional findByEmail(String email) { return userRepository.findByEmail(email); } public Optional findById(Long id) { return userRepository.findById(id); } public Optional findByIdentifier(String identifier) { if (identifier.matches("\\d+")) { return userRepository.findById(Long.parseLong(identifier)); } return userRepository.findByUsername(identifier); } public User updateAvatar(String username, String avatarUrl) { User user = userRepository.findByUsername(username) .orElseThrow(() -> new com.openisle.exception.NotFoundException("User not found")); String old = user.getAvatar(); user.setAvatar(avatarUrl); User saved = userRepository.save(user); if (old != null && !old.equals(avatarUrl)) { imageUploader.removeReferences(java.util.Set.of(old)); } if (avatarUrl != null) { imageUploader.addReferences(java.util.Set.of(avatarUrl)); } return saved; } public User updateReason(String username, String reason) { User user = userRepository.findByUsername(username) .orElseThrow(() -> new com.openisle.exception.NotFoundException("User not found")); user.setRegisterReason(reason); return userRepository.save(user); } public User updateProfile(String currentUsername, String newUsername, String introduction) { User user = userRepository.findByUsername(currentUsername) .orElseThrow(() -> new com.openisle.exception.NotFoundException("User not found")); if (newUsername != null && !newUsername.equals(currentUsername)) { usernameValidator.validate(newUsername); userRepository.findByUsername(newUsername).ifPresent(u -> { throw new FieldException("username", "User name already exists"); }); user.setUsername(newUsername); } if (introduction != null) { user.setIntroduction(introduction); } return userRepository.save(user); } public String generatePasswordResetCode(String email) { User user = userRepository.findByEmail(email) .orElseThrow(() -> new com.openisle.exception.NotFoundException("User not found")); String code = genCode(); user.setPasswordResetCode(code); userRepository.save(user); return code; } public boolean verifyPasswordResetCode(String email, String code) { Optional userOpt = userRepository.findByEmail(email); if (userOpt.isPresent() && code.equals(userOpt.get().getPasswordResetCode())) { User user = userOpt.get(); user.setPasswordResetCode(null); userRepository.save(user); return true; } return false; } public User updatePassword(String username, String newPassword) { passwordValidator.validate(newPassword); User user = userRepository.findByUsername(username) .orElseThrow(() -> new com.openisle.exception.NotFoundException("User not found")); user.setPassword(passwordEncoder.encode(newPassword)); return userRepository.save(user); } /** * Get all administrator accounts. */ public java.util.List getAdmins() { return userRepository.findByRole(Role.ADMIN); } }