diff --git a/src/main/java/dev/codehouse/backend/admin/controller/AdminController.java b/src/main/java/dev/codehouse/backend/admin/controller/AdminController.java index 5f44245..72c76d8 100644 --- a/src/main/java/dev/codehouse/backend/admin/controller/AdminController.java +++ b/src/main/java/dev/codehouse/backend/admin/controller/AdminController.java @@ -7,6 +7,8 @@ import dev.codehouse.backend.global.response.ApiResponse; import dev.codehouse.backend.global.response.ApiResponseFactory; import dev.codehouse.backend.global.response.ResponseCode; +import dev.codehouse.backend.user.dto.UserResponse; +import dev.codehouse.backend.user.service.UserFindService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -21,6 +23,7 @@ public class AdminController { private final AdminNoticeService noticeService; private final AdminPointService pointService; private final AdminProblemService problemService; + private final UserFindService userFindService; @GetMapping("/notice") public ResponseEntity> getNotice() { @@ -38,17 +41,17 @@ public ResponseEntity> adjustPoint(@RequestBody U return ApiResponseFactory.success(ResponseCode.USER_POINT_UPDATED, pointService.adjustUserPoint(dto.getUsername(), dto.getDelta())); } + @GetMapping("/user") + public ResponseEntity>> getAllUsers() { + return ApiResponseFactory.success(ResponseCode.USER_FOUND, userFindService.getAllUsers()); + } + @PostMapping("/problem") public ResponseEntity> register(@RequestBody AdminProblemRequest request) { problemService.saveProblem(request); return ApiResponseFactory.success(ResponseCode.PROBLEM_REGISTERED); } - @GetMapping("/problem/{day}") - public ResponseEntity>> getByDay(@PathVariable String day) { - return ApiResponseFactory.success(ResponseCode.PROBLEM_FOUND, problemService.getProblems(day)); - } - @DeleteMapping("/problem/{number}") public ResponseEntity> deleteProblem(@PathVariable String number) { problemService.deleteProblem(number); diff --git a/src/main/java/dev/codehouse/backend/global/config/SecurityConfig.java b/src/main/java/dev/codehouse/backend/global/config/SecurityConfig.java index 095c731..725d9f5 100644 --- a/src/main/java/dev/codehouse/backend/global/config/SecurityConfig.java +++ b/src/main/java/dev/codehouse/backend/global/config/SecurityConfig.java @@ -1,5 +1,6 @@ package dev.codehouse.backend.global.config; +import dev.codehouse.backend.global.exception.CustomAccessDeniedHandler; import dev.codehouse.backend.global.security.JwtAuthenticationFilter; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; @@ -24,6 +25,7 @@ public class SecurityConfig { @Value("${cors.allowed-origins}") private String allowedOrigins; private final JwtAuthenticationFilter jwtAuthenticationFilter; + private final CustomAccessDeniedHandler customAccessDeniedHandler; // 권한 예외 처리 핸들러 @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @@ -32,6 +34,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable)) .authorizeHttpRequests(auth -> auth .requestMatchers(HttpMethod.GET, "/api/admin/notice").permitAll() + .requestMatchers("/api/admin/**").hasRole("ADMIN") .requestMatchers( "/api/auth/**", "/api/user/ranking/**", @@ -40,6 +43,8 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { ).permitAll() .anyRequest().authenticated() ) + .exceptionHandling(exception -> exception + .accessDeniedHandler(customAccessDeniedHandler)) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); diff --git a/src/main/java/dev/codehouse/backend/global/exception/CustomAccessDeniedHandler.java b/src/main/java/dev/codehouse/backend/global/exception/CustomAccessDeniedHandler.java new file mode 100644 index 0000000..c10ff0c --- /dev/null +++ b/src/main/java/dev/codehouse/backend/global/exception/CustomAccessDeniedHandler.java @@ -0,0 +1,20 @@ +package dev.codehouse.backend.global.exception; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +public class CustomAccessDeniedHandler implements AccessDeniedHandler { + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); // 403 Forbidden + response.setContentType("application/json;charset=UTF-8"); + response.getWriter().write("{\"message\": \"관리자 권한이 필요합니다.\"}"); + } +} diff --git a/src/main/java/dev/codehouse/backend/global/response/ResponseCode.java b/src/main/java/dev/codehouse/backend/global/response/ResponseCode.java index ad2e640..0dd5138 100644 --- a/src/main/java/dev/codehouse/backend/global/response/ResponseCode.java +++ b/src/main/java/dev/codehouse/backend/global/response/ResponseCode.java @@ -30,6 +30,7 @@ public enum ResponseCode { DATABASE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "데이터베이스 오류가 발생했습니다"), EXTERNAL_API_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "외부 API 호출 중 오류가 발생했습니다."), PROBLEM_ALREADY_EXISTS(HttpStatus.INTERNAL_SERVER_ERROR, "이미 존재하는 문제입니다"), + USER_ALREADY_EXISTS(HttpStatus.INTERNAL_SERVER_ERROR, "이미 존재하는 문제입니다"), //200 OK USER_LOGIN_SUCCESS(HttpStatus.OK, "로그인에 성공했습니다."), diff --git a/src/main/java/dev/codehouse/backend/global/security/JwtAuthenticationFilter.java b/src/main/java/dev/codehouse/backend/global/security/JwtAuthenticationFilter.java index 3674615..fc8b062 100644 --- a/src/main/java/dev/codehouse/backend/global/security/JwtAuthenticationFilter.java +++ b/src/main/java/dev/codehouse/backend/global/security/JwtAuthenticationFilter.java @@ -9,12 +9,15 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; +import java.util.Collections; @Slf4j @Component @@ -54,8 +57,12 @@ protected void doFilterInternal( HttpServletRequest request, HttpServletResponse private void setupAuthentication(HttpServletRequest request, String token) { String username = jwtUtil.extractUsername(token); + String role = jwtUtil.extractRole(token); + + GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + role); UsernamePasswordAuthenticationToken authentication = - new UsernamePasswordAuthenticationToken(username, null, null); + new UsernamePasswordAuthenticationToken(username, null, Collections.singletonList(authority)); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authentication); } diff --git a/src/main/java/dev/codehouse/backend/global/util/JwtUtil.java b/src/main/java/dev/codehouse/backend/global/util/JwtUtil.java index af0a362..7b0e1b1 100644 --- a/src/main/java/dev/codehouse/backend/global/util/JwtUtil.java +++ b/src/main/java/dev/codehouse/backend/global/util/JwtUtil.java @@ -29,21 +29,22 @@ public void init() { key = Keys.hmacShaKeyFor(secret.getBytes()); } - private JwtBuilder jwtBuilder(String username, long expirationMills) { + private JwtBuilder jwtBuilder(String username, String role, long expirationMills) { long now = System.currentTimeMillis(); return Jwts.builder() .setSubject(username) + .claim("role", role) .setIssuedAt(new Date(now)) .setExpiration(new Date(now + expirationMills)) .signWith(key); } - public String generateAccessToken(String username) { - return jwtBuilder(username, accessExpiration).compact(); + public String generateAccessToken(String username, String role) { + return jwtBuilder(username, role, accessExpiration).compact(); } - public String generateRefreshToken(String username) { - return jwtBuilder(username, refreshExpiration).compact(); + public String generateRefreshToken(String username, String role) { + return jwtBuilder(username, role, refreshExpiration).compact(); } private io.jsonwebtoken.JwtParser createJwtParser() { @@ -71,4 +72,10 @@ public String extractUsername(String token) { .getSubject(); } + public String extractRole(String token) { + return createJwtParser() + .parseClaimsJws(token) + .getBody() + .get("role", String.class); + } } diff --git a/src/main/java/dev/codehouse/backend/user/controller/AuthController.java b/src/main/java/dev/codehouse/backend/user/controller/AuthController.java index ca80ad8..3e6753c 100644 --- a/src/main/java/dev/codehouse/backend/user/controller/AuthController.java +++ b/src/main/java/dev/codehouse/backend/user/controller/AuthController.java @@ -4,8 +4,7 @@ import dev.codehouse.backend.global.response.ApiResponse; import dev.codehouse.backend.global.response.ApiResponseFactory; import dev.codehouse.backend.global.response.ResponseCode; -import dev.codehouse.backend.user.domain.User; -import dev.codehouse.backend.user.dto.UserRequestDto; +import dev.codehouse.backend.user.dto.UserRequest; import dev.codehouse.backend.user.service.AuthService; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; @@ -21,7 +20,7 @@ public class AuthController { private final AuthService authService; @PostMapping("/register") - public ResponseEntity> register(@RequestBody UserRequestDto request) { + public ResponseEntity> register(@RequestBody UserRequest request) { authService.register(request); return ApiResponseFactory.success(ResponseCode.USER_REGISTER_SUCCESS); } @@ -61,7 +60,7 @@ public ResponseEntity> register(@RequestBody UserRequestDto re // } @PostMapping("/confirm") - public ResponseEntity> confirm(@RequestBody UserRequestDto request) { + public ResponseEntity> confirm(@RequestBody UserRequest request) { authService.userExists(request.getUsername(), request.getClasses()); return ApiResponseFactory.success(ResponseCode.USER_CONFIRM_SUCCESS); } @@ -83,7 +82,7 @@ public ResponseEntity> confirm(@RequestBody UserRequestDto req // return ApiResponseFactory.success(ResponseCode.USER_LOGIN_SUCCESS, tokens); // } @PostMapping("/login") - public ResponseEntity>> login(@RequestBody UserRequestDto request) { + public ResponseEntity>> login(@RequestBody UserRequest request) { Map tokens = authService.login(request); return ApiResponseFactory.success(ResponseCode.USER_LOGIN_SUCCESS,tokens); } diff --git a/src/main/java/dev/codehouse/backend/user/controller/UserController.java b/src/main/java/dev/codehouse/backend/user/controller/UserController.java index d020a41..f2c4146 100644 --- a/src/main/java/dev/codehouse/backend/user/controller/UserController.java +++ b/src/main/java/dev/codehouse/backend/user/controller/UserController.java @@ -5,8 +5,8 @@ import dev.codehouse.backend.global.response.ResponseCode; import dev.codehouse.backend.user.domain.User; import dev.codehouse.backend.user.domain.UserHistory; -import dev.codehouse.backend.user.dto.RankingResponseDto; -import dev.codehouse.backend.user.dto.UserResponseDto; +import dev.codehouse.backend.user.dto.RankingResponse; +import dev.codehouse.backend.user.dto.UserResponse; import dev.codehouse.backend.user.repository.UserRepository; import dev.codehouse.backend.user.service.UserFindService; import dev.codehouse.backend.user.service.UserHistoryService; @@ -28,36 +28,27 @@ public class UserController { private final UserFindService userFindService; - private final UserRepository userRepository; private final UserRankingService userRankingService; private final UserHistoryService userHistoryService; - @GetMapping("/{username}") - public ResponseEntity> getUser(@PathVariable String username) { - return ApiResponseFactory.success(ResponseCode.USER_FOUND, userFindService.getUser(username)); + @GetMapping("/me") + public ResponseEntity> getUser(Authentication authentication) { + return ApiResponseFactory.success(ResponseCode.USER_FOUND, userFindService.getUser(authentication.getName())); } @GetMapping("") - public ResponseEntity>> getAllUsers() { + public ResponseEntity>> getAllUsers() { return ApiResponseFactory.success(ResponseCode.USER_FOUND, userFindService.getAllUsers()); } - - @GetMapping("/{username}/point") - public Map getPoint(@PathVariable String username) { - User user = userRepository.findByUsername(username) - .orElseThrow(() -> new RuntimeException("존재하지 않는 사용자입니다.")); - return Map.of("point", user.getPoint()); - } - @GetMapping("/ranking") - public ResponseEntity>> getTopRanking(){ + public ResponseEntity>> getTopRanking(){ return ApiResponseFactory.success(ResponseCode.RANK_FOUND,userRankingService.getTopRanking()); } @GetMapping("/ranking/{className}") - public ResponseEntity>> getClassRanking(@PathVariable String className){ - return ApiResponseFactory.success(ResponseCode.RANK_FOUND,userRankingService.getclassRanking(className)); + public ResponseEntity>> getClassRanking(@PathVariable String className){ + return ApiResponseFactory.success(ResponseCode.RANK_FOUND,userRankingService.getClassRanking(className)); } @GetMapping("/history") diff --git a/src/main/java/dev/codehouse/backend/user/controller/UserHistoryController.java b/src/main/java/dev/codehouse/backend/user/controller/UserHistoryController.java deleted file mode 100644 index 3575295..0000000 --- a/src/main/java/dev/codehouse/backend/user/controller/UserHistoryController.java +++ /dev/null @@ -1,25 +0,0 @@ -package dev.codehouse.backend.user.controller; - -import dev.codehouse.backend.user.dto.HistoryRequest; -import dev.codehouse.backend.user.service.UserHistoryService; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.*; - -import java.util.List; - -@Controller -@RequiredArgsConstructor -@RequestMapping("/api/history") -public class UserHistoryController { - private final UserHistoryService userHistoryService; - - @PostMapping("/add") - public ResponseEntity addHistory( - @RequestBody HistoryRequest request - ) { - userHistoryService.addUserHistory(request.getUsername(), request.getType(), request.getReason(), request.getAmount()); - return ResponseEntity.ok("history 에 추가 완료"); - } -} diff --git a/src/main/java/dev/codehouse/backend/user/dto/HistoryRequest.java b/src/main/java/dev/codehouse/backend/user/dto/HistoryRequest.java deleted file mode 100644 index 33d6ab2..0000000 --- a/src/main/java/dev/codehouse/backend/user/dto/HistoryRequest.java +++ /dev/null @@ -1,14 +0,0 @@ -package dev.codehouse.backend.user.dto; - -import dev.codehouse.backend.user.domain.HistoryType; -import lombok.Getter; -import lombok.Setter; - -@Getter -@Setter -public class HistoryRequest { - private String username; - private HistoryType type; - private String reason; - private int amount; -} diff --git a/src/main/java/dev/codehouse/backend/user/dto/RankingResponse.java b/src/main/java/dev/codehouse/backend/user/dto/RankingResponse.java new file mode 100644 index 0000000..a8626c8 --- /dev/null +++ b/src/main/java/dev/codehouse/backend/user/dto/RankingResponse.java @@ -0,0 +1,32 @@ +package dev.codehouse.backend.user.dto; + + +import dev.codehouse.backend.user.domain.User; +import lombok.*; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class RankingResponse { + private String username; + private int point; + private int rank; + private String classes; + + public static List from(List users) { + AtomicInteger rank = new AtomicInteger(1); + + return users.stream() + .map(user -> RankingResponse.builder() + .username(user.getUsername()) + .point(user.getPoint()) + .rank(rank.getAndIncrement()) + .classes(user.getClasses()) + .build()) + .toList(); + } +} diff --git a/src/main/java/dev/codehouse/backend/user/dto/RankingResponseDto.java b/src/main/java/dev/codehouse/backend/user/dto/RankingResponseDto.java deleted file mode 100644 index ab729ab..0000000 --- a/src/main/java/dev/codehouse/backend/user/dto/RankingResponseDto.java +++ /dev/null @@ -1,18 +0,0 @@ -package dev.codehouse.backend.user.dto; - - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class RankingResponseDto { - private String username; - private int point; - private int rank; - private String classes; -} diff --git a/src/main/java/dev/codehouse/backend/user/dto/UserRequestDto.java b/src/main/java/dev/codehouse/backend/user/dto/UserRequest.java similarity index 86% rename from src/main/java/dev/codehouse/backend/user/dto/UserRequestDto.java rename to src/main/java/dev/codehouse/backend/user/dto/UserRequest.java index 7a04e7b..951ae23 100644 --- a/src/main/java/dev/codehouse/backend/user/dto/UserRequestDto.java +++ b/src/main/java/dev/codehouse/backend/user/dto/UserRequest.java @@ -5,7 +5,7 @@ @Getter @Setter -public class UserRequestDto { +public class UserRequest { private String username; private String password; private String classes; diff --git a/src/main/java/dev/codehouse/backend/user/dto/UserResponseDto.java b/src/main/java/dev/codehouse/backend/user/dto/UserResponse.java similarity index 75% rename from src/main/java/dev/codehouse/backend/user/dto/UserResponseDto.java rename to src/main/java/dev/codehouse/backend/user/dto/UserResponse.java index f7e272f..8bec08e 100644 --- a/src/main/java/dev/codehouse/backend/user/dto/UserResponseDto.java +++ b/src/main/java/dev/codehouse/backend/user/dto/UserResponse.java @@ -6,13 +6,13 @@ @Getter @AllArgsConstructor -public class UserResponseDto { +public class UserResponse { private String username; private String classes; private int point; - public static UserResponseDto from(User user) { - return new UserResponseDto( + public static UserResponse from(User user) { + return new UserResponse( user.getUsername(), user.getClasses(), user.getPoint() diff --git a/src/main/java/dev/codehouse/backend/user/service/AuthService.java b/src/main/java/dev/codehouse/backend/user/service/AuthService.java index 081b00d..3d61b59 100644 --- a/src/main/java/dev/codehouse/backend/user/service/AuthService.java +++ b/src/main/java/dev/codehouse/backend/user/service/AuthService.java @@ -4,21 +4,14 @@ import dev.codehouse.backend.global.exception.AuthException; import dev.codehouse.backend.global.response.ResponseCode; import dev.codehouse.backend.user.domain.User; -import dev.codehouse.backend.user.dto.UserRequestDto; +import dev.codehouse.backend.user.dto.UserRequest; import dev.codehouse.backend.user.repository.UserRepository; import dev.codehouse.backend.global.util.JwtUtil; import dev.codehouse.backend.user.service.external.SolvedAcClient; import lombok.RequiredArgsConstructor; -import org.springframework.dao.DuplicateKeyException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.HashMap; -import java.util.List; import java.util.Map; /** @@ -48,7 +41,7 @@ public void userExists(String username, String className) { } } - private void validateRequest(UserRequestDto request) { + private void validateRequest(UserRequest request) { if (request == null || request.getUsername() == null || request.getPassword() == null) { throw new AuthException(ResponseCode.INVALID_REQUEST); } @@ -61,11 +54,11 @@ private void validateRequest(UserRequestDto request) { * @throws IllegalArgumentException 이미 존재하는 사용자이거나 클래스 정보가 유효하지 않은 경우 * @throws RuntimeException API 호출 실패시 */ - public void register(UserRequestDto request) { + public void register(UserRequest request) { validateRequest(request); if(userRepository.existsByUsername(request.getUsername())){ - throw new DuplicateKeyException("이미 존재하는 사용자입니다."); + throw new AuthException(ResponseCode.USER_ALREADY_EXISTS); } User user = User.of(request.getUsername(), passwordEncoder.encode(request.getPassword()),request.getClasses()); userRepository.save(user); @@ -79,7 +72,7 @@ public void register(UserRequestDto request) { * @return 액세스 토큰과 리프레시 토큰이 담긴 Map * @throws IllegalArgumentException 사용자를 찾을 수 없거나 비밀번호가 일치하지 않는 경우 */ - public Map login(UserRequestDto request) { + public Map login(UserRequest request) { validateRequest(request); User user = userRepository.findByUsername(request.getUsername()) .orElseThrow(() -> new AuthException(ResponseCode.USER_NOT_FOUND)); @@ -89,8 +82,8 @@ public Map login(UserRequestDto request) { } return Map.of( - "accessToken", jwtUtil.generateAccessToken(user.getUsername()), - "refreshToken", jwtUtil.generateRefreshToken(user.getUsername()) + "accessToken", jwtUtil.generateAccessToken(user.getUsername(), user.getRole()), + "refreshToken", jwtUtil.generateRefreshToken(user.getUsername(), user.getRole()) ); } diff --git a/src/main/java/dev/codehouse/backend/user/service/UserFindService.java b/src/main/java/dev/codehouse/backend/user/service/UserFindService.java index 123feaf..9bf6ee8 100644 --- a/src/main/java/dev/codehouse/backend/user/service/UserFindService.java +++ b/src/main/java/dev/codehouse/backend/user/service/UserFindService.java @@ -3,7 +3,7 @@ import dev.codehouse.backend.global.exception.UserException; import dev.codehouse.backend.global.response.ResponseCode; import dev.codehouse.backend.user.domain.User; -import dev.codehouse.backend.user.dto.UserResponseDto; +import dev.codehouse.backend.user.dto.UserResponse; import dev.codehouse.backend.user.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -16,16 +16,16 @@ public class UserFindService { private final UserRepository userRepository; - public UserResponseDto getUser(String username) { + public UserResponse getUser(String username) { User user = userRepository.findByUsername(username) .orElseThrow(() -> new UserException(ResponseCode.USER_NOT_FOUND)); - return UserResponseDto.from(user); + return UserResponse.from(user); } - public List getAllUsers() { + public List getAllUsers() { List users = userRepository.findAll(); return users.stream() - .map(UserResponseDto::from) + .map(UserResponse::from) .toList(); } } diff --git a/src/main/java/dev/codehouse/backend/user/service/UserHistoryService.java b/src/main/java/dev/codehouse/backend/user/service/UserHistoryService.java index 2f6b3d9..a8f9abe 100644 --- a/src/main/java/dev/codehouse/backend/user/service/UserHistoryService.java +++ b/src/main/java/dev/codehouse/backend/user/service/UserHistoryService.java @@ -2,38 +2,22 @@ import dev.codehouse.backend.global.exception.UserException; import dev.codehouse.backend.global.response.ResponseCode; -import dev.codehouse.backend.user.domain.HistoryType; import dev.codehouse.backend.user.domain.UserHistory; import dev.codehouse.backend.user.domain.User; import dev.codehouse.backend.user.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; import java.util.List; @Service @RequiredArgsConstructor public class UserHistoryService { - private final UserRepository userRepository; - - public void addUserHistory(String username, HistoryType type, String reason, int amount) { - User user = userRepository.findByUsername(username) - .orElseThrow(() -> new UserException(ResponseCode.USER_NOT_FOUND)); - UserHistory userHistory = new UserHistory(LocalDateTime.now(), username, type, reason, amount); - user.getHistories().add(userHistory); - - // 포인트 수정 코드 - // 필요시 추가 할 것 - // user.setPoint(user.getPoint() + amount); - userRepository.save(user); - } + private final UserRepository userRepository; public List getUserHistory(String username) { User user = userRepository.findByUsername(username) .orElseThrow(() -> new UserException(ResponseCode.USER_NOT_FOUND)); - return user.getHistories(); } } diff --git a/src/main/java/dev/codehouse/backend/user/service/UserRankingService.java b/src/main/java/dev/codehouse/backend/user/service/UserRankingService.java index 30ec403..f03e95b 100644 --- a/src/main/java/dev/codehouse/backend/user/service/UserRankingService.java +++ b/src/main/java/dev/codehouse/backend/user/service/UserRankingService.java @@ -1,90 +1,32 @@ package dev.codehouse.backend.user.service; import dev.codehouse.backend.user.domain.User; -import dev.codehouse.backend.user.dto.RankingResponseDto; +import dev.codehouse.backend.user.dto.RankingResponse; import dev.codehouse.backend.user.repository.UserRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor -@Slf4j public class UserRankingService { private final UserRepository userRepository; - /** - * 전체 사용자 중 상위 5명 랭킹 조회 - */ - public List getTopRanking(){ - log.info("전체 랭킹 조회 시작 - 상위 5명"); - + public List getTopRanking(){ List topUsers = userRepository.findAllByOrderByPointDesc( PageRequest.of(0,5) ); - - return convertToRankingDto(topUsers); + return RankingResponse.from(topUsers); } - /** - * 특정 회차별 상위 5명 랭킹 조회 - */ - public List getclassRanking(String className) { - log.info("회차별 랭킹 조회 시작 - 회차 : {}, 상위 5명", className); + public List getClassRanking(String className) { List classUsers = userRepository.findByClassesOrderByPointDesc(className, PageRequest.of(0,5)); - - return convertToRankingDto(classUsers); - } - - /** - * 특정 사용자의 전체 등수 조회 - */ - public int getUserOverallRank(String username) { - log.info("사용자 전체 등수 조회 - username={}", username); - Optional user = userRepository.findByUsername(username); - if(user.isPresent()){ - long higherRankedCount = userRepository.countByPointGreaterThan(user.get().getPoint()); - return (int)higherRankedCount + 1; - } else { - throw new IllegalArgumentException("사용자를 찾을 수 없습니다: "); - } - } - - /** - * 특정 사용자의 회차별 등수 조회 - */ - public int getUserClassRank(String username) { - log.info("사용자 회차별 등수 조회 - username: {}, ", username); - - Optional user = userRepository.findByUsername(username); - if(user.isPresent()){ - String userClasses = user.get().getClasses(); - long higherRankedCount = userRepository.countByClassesAndPointGreaterThan(user.get().getClasses(), user.get().getPoint()); - return (int)higherRankedCount + 1; - } - else { - throw new IllegalArgumentException("사용자를 찾을 수 없습니다."); - } - } - - private List convertToRankingDto(List users) { - AtomicInteger rank = new AtomicInteger(1); - - return users.stream() - .map(user -> RankingResponseDto.builder() - .username(user.getUsername()) - .point(user.getPoint()) - .rank(rank.getAndIncrement()) - .classes(user.getClasses()) - .build()) - .toList(); + return RankingResponse.from(classUsers); } }