AdminUserService.java
package com.hwhub.backend.application.service;
import com.hwhub.backend.domain.enums.Permission;
import com.hwhub.backend.domain.enums.ProgramType;
import com.hwhub.backend.domain.model.AdminUserSearchCondition;
import com.hwhub.backend.domain.model.UserModel;
import com.hwhub.backend.domain.repository.UserRepository;
import com.hwhub.backend.presentation.rest.common.EmailAlreadyUsedException;
import com.hwhub.backend.presentation.rest.common.ResourceNotFoundException;
import com.hwhub.backend.security.RequiresPermission;
import java.time.LocalDateTime;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
public class AdminUserService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
private final UserIconService userIconService;
/**
* 管理者用ユーザー検索
*
* @param condition 検索条件
* @return ユーザーリスト
*/
@RequiresPermission(Permission.USER_LIST_VIEW)
@Transactional(readOnly = true)
public List<UserModel> searchUsers(AdminUserSearchCondition condition) {
List<UserModel> users = userRepository.searchByCondition(condition);
users.forEach(u -> u.setIconUrl(userIconService.getIconUrl(u.getProfileImageKey())));
return users;
}
/**
* 管理者専用ユーザー登録。 メール認証スキップ・即時 active・email_verified_at を NOW でセット。
*
* @param email メールアドレス
* @param password パスワード
* @param displayName 表示名
* @param locale ロケール
* @param operatorUserId 操作者ID
* @return 作成されたユーザー
* @throws EmailAlreadyUsedException メールアドレスが既に使用されている場合
*/
@RequiresPermission(Permission.USER_LIST_VIEW)
@Transactional
public UserModel createUser(
String email, String password, String displayName, String locale, Long operatorUserId) {
userRepository
.findByEmail(email)
.ifPresent(
existing -> {
throw new EmailAlreadyUsedException(email);
});
UserModel model = UserModel.create(email, password, displayName, locale);
String hash = passwordEncoder.encode(password);
model.setPasswordHash(hash);
UserModel created =
userRepository.insertByAdmin(model, operatorUserId, ProgramType.ONL_ADM_USR.getCode());
userRepository.markEmailVerified(
created.getUserId(),
LocalDateTime.now(),
operatorUserId,
ProgramType.ONL_ADM_USR.getCode());
return created;
}
/**
* 管理者によるユーザー情報更新。 password は null/空白の場合は変更しない。
*
* @param targetUserId 対象ユーザーID
* @param displayName 表示名
* @param locale ロケール
* @param password パスワード
* @param isActive アクティブ状態
* @param operatorUserId 操作者ID
* @return 更新されたユーザー
* @throws ResourceNotFoundException ユーザーが見つからない場合
*/
@RequiresPermission(Permission.USER_LIST_VIEW)
@Transactional
public UserModel updateUser(
Long targetUserId,
String displayName,
String locale,
String password,
Boolean isActive,
Long operatorUserId) {
UserModel user =
userRepository
.findById(targetUserId)
.orElseThrow(() -> new ResourceNotFoundException("User not found: " + targetUserId));
user.changeProfile(displayName, locale);
if (isActive != null) {
if (isActive) {
user.activate();
} else {
user.deactivate();
}
}
if (password != null && !password.isBlank()) {
String hash = passwordEncoder.encode(password);
user.setPasswordHash(hash);
}
userRepository.updateByAdmin(user, operatorUserId, ProgramType.ONL_ADM_USR.getCode());
return user;
}
}