gc-guide-api/src/main/java/com/gcsc/guide/service/UserService.java
htlee 9db7b8bfb4 feat: 관리자/활동/이슈 API 전체 구현
- Entity: LoginHistory, PageView, Issue, IssueComment 추가
- Repository: 각 엔티티별 JpaRepository 추가
- Service: UserService, RoleService, ActivityService, IssueService
- Admin API: 사용자 관리 7개, 롤/권한 관리 7개, 통계 1개 엔드포인트
- Activity API: 페이지뷰 기록, 로그인 이력 조회
- Issue API: CRUD + 코멘트, 프로젝트/위치/Gitea 링크 지원
- Exception: GlobalExceptionHandler, ResourceNotFoundException, BusinessException
- AuthController: 로그인 시 LoginHistory 기록 추가
- Dockerfile 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 21:13:14 +09:00

121 lines
4.4 KiB
Java

package com.gcsc.guide.service;
import com.gcsc.guide.dto.StatsResponse;
import com.gcsc.guide.dto.UserResponse;
import com.gcsc.guide.entity.Role;
import com.gcsc.guide.entity.User;
import com.gcsc.guide.entity.UserStatus;
import com.gcsc.guide.exception.BusinessException;
import com.gcsc.guide.exception.ResourceNotFoundException;
import com.gcsc.guide.repository.LoginHistoryRepository;
import com.gcsc.guide.repository.RoleRepository;
import com.gcsc.guide.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Service
@RequiredArgsConstructor
public class UserService {
private final UserRepository userRepository;
private final RoleRepository roleRepository;
private final LoginHistoryRepository loginHistoryRepository;
@Transactional(readOnly = true)
public List<UserResponse> getUsers(String status) {
List<User> users;
if (status != null && !status.isBlank()) {
UserStatus userStatus = UserStatus.valueOf(status.toUpperCase());
users = userRepository.findByStatus(userStatus);
} else {
users = userRepository.findAll();
}
return users.stream().map(UserResponse::from).toList();
}
@Transactional
public UserResponse approveUser(Long userId) {
User user = findUserById(userId);
if (user.getStatus() != UserStatus.PENDING) {
throw new BusinessException("PENDING 상태의 사용자만 승인할 수 있습니다 (현재: " + user.getStatus() + ")");
}
user.activate();
return UserResponse.from(userRepository.save(user));
}
@Transactional
public UserResponse rejectUser(Long userId) {
User user = findUserById(userId);
if (user.getStatus() != UserStatus.PENDING) {
throw new BusinessException("PENDING 상태의 사용자만 거절할 수 있습니다 (현재: " + user.getStatus() + ")");
}
user.reject();
return UserResponse.from(userRepository.save(user));
}
@Transactional
public UserResponse disableUser(Long userId) {
User user = findUserById(userId);
if (user.getStatus() != UserStatus.ACTIVE) {
throw new BusinessException("ACTIVE 상태의 사용자만 비활성화할 수 있습니다 (현재: " + user.getStatus() + ")");
}
user.disable();
return UserResponse.from(userRepository.save(user));
}
@Transactional
public UserResponse updateUserRoles(Long userId, List<Long> roleIds) {
User user = findUserById(userId);
Set<Role> roles = new HashSet<>(roleRepository.findAllById(roleIds));
if (roles.size() != roleIds.size()) {
throw new BusinessException("일부 롤을 찾을 수 없습니다");
}
user.updateRoles(roles);
userRepository.save(user);
return UserResponse.from(userRepository.findByIdWithRoles(userId).orElseThrow());
}
@Transactional
public UserResponse grantAdmin(Long userId) {
User user = findUserById(userId);
user.grantAdmin();
return UserResponse.from(userRepository.save(user));
}
@Transactional
public UserResponse revokeAdmin(Long userId) {
User user = findUserById(userId);
user.revokeAdmin();
return UserResponse.from(userRepository.save(user));
}
@Transactional(readOnly = true)
public StatsResponse getStats() {
long totalUsers = userRepository.count();
long activeUsers = userRepository.countByStatus(UserStatus.ACTIVE);
long pendingUsers = userRepository.countByStatus(UserStatus.PENDING);
long rejectedUsers = userRepository.countByStatus(UserStatus.REJECTED);
long disabledUsers = userRepository.countByStatus(UserStatus.DISABLED);
long todayLogins = loginHistoryRepository.countByLoginAtAfter(
LocalDate.now().atStartOfDay());
long totalRoles = roleRepository.count();
return new StatsResponse(
totalUsers, activeUsers, pendingUsers,
rejectedUsers, disabledUsers, todayLogins, totalRoles
);
}
private User findUserById(Long userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new ResourceNotFoundException("사용자", userId));
}
}