diff --git a/src/main/java/ssurent/ssurentbe/common/status/SuccessStatus.java b/src/main/java/ssurent/ssurentbe/common/status/SuccessStatus.java index d215307..93493de 100644 --- a/src/main/java/ssurent/ssurentbe/common/status/SuccessStatus.java +++ b/src/main/java/ssurent/ssurentbe/common/status/SuccessStatus.java @@ -16,8 +16,9 @@ public enum SuccessStatus implements BaseStatus { LOGOUT_SUCCESS(HttpStatus.OK, "AUTH_200", "로그아웃 성공"), REISSUE_TOKEN_SUCCESS(HttpStatus.OK, "AUTH_200", "토큰 재발급 성공"), WITHDRAW_SUCCESS(HttpStatus.OK, "AUTH_200", "회원탈퇴 성공"), - SIGNUP_SUCCESS(HttpStatus.CREATED, "AUTH_201", "회원가입 성공"); + SIGNUP_SUCCESS(HttpStatus.CREATED, "AUTH_201", "회원가입 성공"), + PANELTY_CHECK_SUCCESS(HttpStatus.OK, "PANELTY_200", "징계내역 조회 성공"); private final HttpStatus httpStatus; private final String code; private final String message; diff --git a/src/main/java/ssurent/ssurentbe/domain/users/controller/AuthController.java b/src/main/java/ssurent/ssurentbe/domain/users/controller/AuthController.java index 3f8a473..325d090 100644 --- a/src/main/java/ssurent/ssurentbe/domain/users/controller/AuthController.java +++ b/src/main/java/ssurent/ssurentbe/domain/users/controller/AuthController.java @@ -6,9 +6,9 @@ import ssurent.ssurentbe.common.base.BaseResponse; import ssurent.ssurentbe.common.status.SuccessStatus; import ssurent.ssurentbe.domain.users.controller.docs.AuthApiDocs; -import ssurent.ssurentbe.domain.users.dto.LoginRequest; -import ssurent.ssurentbe.domain.users.dto.SignupRequest; -import ssurent.ssurentbe.domain.users.dto.TokenResponse; +import ssurent.ssurentbe.domain.users.dto.request.LoginRequest; +import ssurent.ssurentbe.domain.users.dto.request.SignupRequest; +import ssurent.ssurentbe.domain.users.dto.response.TokenResponse; import ssurent.ssurentbe.domain.users.service.AuthService; @RestController diff --git a/src/main/java/ssurent/ssurentbe/domain/users/controller/UserController.java b/src/main/java/ssurent/ssurentbe/domain/users/controller/UserController.java new file mode 100644 index 0000000..30e10c3 --- /dev/null +++ b/src/main/java/ssurent/ssurentbe/domain/users/controller/UserController.java @@ -0,0 +1,52 @@ +package ssurent.ssurentbe.domain.users.controller; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.web.bind.annotation.*; +import ssurent.ssurentbe.common.base.BaseResponse; +import ssurent.ssurentbe.common.status.SuccessStatus; +import ssurent.ssurentbe.domain.users.dto.request.UpdatePhoneNumberRequest; +import ssurent.ssurentbe.domain.users.dto.response.UserInfoResponse; +import ssurent.ssurentbe.domain.users.dto.response.UserPenaltyResponse; +import ssurent.ssurentbe.domain.users.service.UserQueryService; +import ssurent.ssurentbe.domain.users.service.UserCommandService; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/v1/api/users") +public class UserController { + private final UserQueryService userQueryService; + private final UserCommandService userCommandService; + + @GetMapping + public UserInfoResponse getMyInfo(@AuthenticationPrincipal UserDetails userDetails) { + return userQueryService.getMyInfo(userDetails.getUsername()); + } + + @PatchMapping("/phone-number") + public ResponseEntity updatePhoneNumber( + @AuthenticationPrincipal UserDetails userDetails, + @Valid @RequestBody UpdatePhoneNumberRequest request + ) { + userCommandService.updatePhoneNumber( + userDetails.getUsername(), + request.phoneNum() + ); + return ResponseEntity.noContent().build(); + } + @GetMapping("/penalties") + public ResponseEntity>> getMyPenalties( + @AuthenticationPrincipal UserDetails userDetails + ) { + List data = userQueryService.getMyPenalties(userDetails.getUsername()); + SuccessStatus status = SuccessStatus.PANELTY_CHECK_SUCCESS; + return ResponseEntity.status(status.getHttpStatus()) + .body(BaseResponse.success(status, data)); + } + +} diff --git a/src/main/java/ssurent/ssurentbe/domain/users/controller/docs/AuthApiDocs.java b/src/main/java/ssurent/ssurentbe/domain/users/controller/docs/AuthApiDocs.java index ea8d199..8151aba 100644 --- a/src/main/java/ssurent/ssurentbe/domain/users/controller/docs/AuthApiDocs.java +++ b/src/main/java/ssurent/ssurentbe/domain/users/controller/docs/AuthApiDocs.java @@ -10,10 +10,10 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import ssurent.ssurentbe.common.base.BaseResponse; -import ssurent.ssurentbe.domain.users.dto.LoginRequest; -import ssurent.ssurentbe.domain.users.dto.SignupRequest; -import ssurent.ssurentbe.domain.users.dto.TokenResponse; -import ssurent.ssurentbe.domain.users.dto.TokenResponseWrapper; +import ssurent.ssurentbe.domain.users.dto.request.LoginRequest; +import ssurent.ssurentbe.domain.users.dto.request.SignupRequest; +import ssurent.ssurentbe.domain.users.dto.response.TokenResponse; +import ssurent.ssurentbe.domain.users.dto.response.TokenResponseWrapper; @Tag(name = "Auth", description = "인증 API") public interface AuthApiDocs { diff --git a/src/main/java/ssurent/ssurentbe/domain/users/dto/LoginRequest.java b/src/main/java/ssurent/ssurentbe/domain/users/dto/request/LoginRequest.java similarity index 62% rename from src/main/java/ssurent/ssurentbe/domain/users/dto/LoginRequest.java rename to src/main/java/ssurent/ssurentbe/domain/users/dto/request/LoginRequest.java index e56997d..2dc2c5f 100644 --- a/src/main/java/ssurent/ssurentbe/domain/users/dto/LoginRequest.java +++ b/src/main/java/ssurent/ssurentbe/domain/users/dto/request/LoginRequest.java @@ -1,4 +1,4 @@ -package ssurent.ssurentbe.domain.users.dto; +package ssurent.ssurentbe.domain.users.dto.request; public record LoginRequest( String studentNum, diff --git a/src/main/java/ssurent/ssurentbe/domain/users/dto/SignupRequest.java b/src/main/java/ssurent/ssurentbe/domain/users/dto/request/SignupRequest.java similarity index 87% rename from src/main/java/ssurent/ssurentbe/domain/users/dto/SignupRequest.java rename to src/main/java/ssurent/ssurentbe/domain/users/dto/request/SignupRequest.java index eef27bd..af0bbb0 100644 --- a/src/main/java/ssurent/ssurentbe/domain/users/dto/SignupRequest.java +++ b/src/main/java/ssurent/ssurentbe/domain/users/dto/request/SignupRequest.java @@ -1,4 +1,4 @@ -package ssurent.ssurentbe.domain.users.dto; +package ssurent.ssurentbe.domain.users.dto.request; public record SignupRequest( String studentNum, diff --git a/src/main/java/ssurent/ssurentbe/domain/users/dto/request/UpdatePhoneNumberRequest.java b/src/main/java/ssurent/ssurentbe/domain/users/dto/request/UpdatePhoneNumberRequest.java new file mode 100644 index 0000000..53ed0a2 --- /dev/null +++ b/src/main/java/ssurent/ssurentbe/domain/users/dto/request/UpdatePhoneNumberRequest.java @@ -0,0 +1,11 @@ +package ssurent.ssurentbe.domain.users.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; + +public record UpdatePhoneNumberRequest( + @NotBlank(message = "전화번호는 필수 입력값입니다.") + @Pattern(regexp = "^01[016789]-?\\d{3,4}-?\\d{4}$", message = "올바른 전화번호 형식이 아닙니다.") + String phoneNum +) { +} diff --git a/src/main/java/ssurent/ssurentbe/domain/users/dto/TokenResponse.java b/src/main/java/ssurent/ssurentbe/domain/users/dto/response/TokenResponse.java similarity index 83% rename from src/main/java/ssurent/ssurentbe/domain/users/dto/TokenResponse.java rename to src/main/java/ssurent/ssurentbe/domain/users/dto/response/TokenResponse.java index 8d33d09..01e9cb1 100644 --- a/src/main/java/ssurent/ssurentbe/domain/users/dto/TokenResponse.java +++ b/src/main/java/ssurent/ssurentbe/domain/users/dto/response/TokenResponse.java @@ -1,4 +1,4 @@ -package ssurent.ssurentbe.domain.users.dto; +package ssurent.ssurentbe.domain.users.dto.response; public record TokenResponse( String accessToken, diff --git a/src/main/java/ssurent/ssurentbe/domain/users/dto/TokenResponseWrapper.java b/src/main/java/ssurent/ssurentbe/domain/users/dto/response/TokenResponseWrapper.java similarity index 86% rename from src/main/java/ssurent/ssurentbe/domain/users/dto/TokenResponseWrapper.java rename to src/main/java/ssurent/ssurentbe/domain/users/dto/response/TokenResponseWrapper.java index dbbc6dd..e0f4140 100644 --- a/src/main/java/ssurent/ssurentbe/domain/users/dto/TokenResponseWrapper.java +++ b/src/main/java/ssurent/ssurentbe/domain/users/dto/response/TokenResponseWrapper.java @@ -1,4 +1,4 @@ -package ssurent.ssurentbe.domain.users.dto; +package ssurent.ssurentbe.domain.users.dto.response; import io.swagger.v3.oas.annotations.media.Schema; import ssurent.ssurentbe.common.base.BaseResponse; diff --git a/src/main/java/ssurent/ssurentbe/domain/users/dto/response/UserInfoResponse.java b/src/main/java/ssurent/ssurentbe/domain/users/dto/response/UserInfoResponse.java new file mode 100644 index 0000000..f0c84ef --- /dev/null +++ b/src/main/java/ssurent/ssurentbe/domain/users/dto/response/UserInfoResponse.java @@ -0,0 +1,23 @@ +package ssurent.ssurentbe.domain.users.dto.response; + +import ssurent.ssurentbe.domain.users.entity.Users; +import ssurent.ssurentbe.domain.users.enums.Role; +import ssurent.ssurentbe.domain.users.enums.Status; + +public record UserInfoResponse( + String studentNum, + String name, + String phoneNum, + Status status, + Role role +) { + public static UserInfoResponse from(Users user) { + return new UserInfoResponse( + user.getStudentNum(), + user.getName(), + user.getPhoneNum(), + user.getStatus(), + user.getRole() + ); + } +} \ No newline at end of file diff --git a/src/main/java/ssurent/ssurentbe/domain/users/dto/response/UserPenaltyResponse.java b/src/main/java/ssurent/ssurentbe/domain/users/dto/response/UserPenaltyResponse.java index ded7f15..cddfa18 100644 --- a/src/main/java/ssurent/ssurentbe/domain/users/dto/response/UserPenaltyResponse.java +++ b/src/main/java/ssurent/ssurentbe/domain/users/dto/response/UserPenaltyResponse.java @@ -1,25 +1,24 @@ package ssurent.ssurentbe.domain.users.dto.response; -import ssurent.ssurentbe.domain.item.entity.Items; import ssurent.ssurentbe.domain.users.entity.UserPenaltyLog; +import ssurent.ssurentbe.domain.users.enums.PenaltyTypes; import java.time.LocalDateTime; public record UserPenaltyResponse( - Long userPenaltyId, - LocalDateTime createdAt, - String itemName, - String penaltyType + Long penaltyId, + PenaltyTypes penaltyType, + Long itemId, + Long rentalHistoryId, + LocalDateTime createdAt ) { - public static UserPenaltyResponse from(UserPenaltyLog userPenaltyLog) { - Items item = userPenaltyLog.getItemsId(); - String itemInfo = item.getName() + " (" + item.getItemNum() + ")"; - + public static UserPenaltyResponse from(UserPenaltyLog log) { return new UserPenaltyResponse( - userPenaltyLog.getId(), - userPenaltyLog.getCreatedAt(), - itemInfo, - userPenaltyLog.getPenaltyType().getDescription() + log.getId(), + log.getPenaltyType(), + log.getItemsId() != null ? log.getItemsId().getId() : null, + log.getRentalHistoryId() != null ? log.getRentalHistoryId().getId() : null, + log.getCreatedAt() ); } } diff --git a/src/main/java/ssurent/ssurentbe/domain/users/entity/Users.java b/src/main/java/ssurent/ssurentbe/domain/users/entity/Users.java index 5334ddb..a14df53 100644 --- a/src/main/java/ssurent/ssurentbe/domain/users/entity/Users.java +++ b/src/main/java/ssurent/ssurentbe/domain/users/entity/Users.java @@ -52,4 +52,8 @@ public void withdraw(){ this.phoneNum = null; this.studentNum = null; } + public void updatePhoneNumber(String phoneNum) { + this.phoneNum = phoneNum; + } + } diff --git a/src/main/java/ssurent/ssurentbe/domain/users/repository/UserPenaltyLogRepository.java b/src/main/java/ssurent/ssurentbe/domain/users/repository/UserPenaltyLogRepository.java new file mode 100644 index 0000000..4e037d4 --- /dev/null +++ b/src/main/java/ssurent/ssurentbe/domain/users/repository/UserPenaltyLogRepository.java @@ -0,0 +1,12 @@ +package ssurent.ssurentbe.domain.users.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import ssurent.ssurentbe.domain.users.entity.UserPenaltyLog; +import ssurent.ssurentbe.domain.users.entity.Users; + +import java.util.List; + +public interface UserPenaltyLogRepository extends JpaRepository { + + List findByUserIdOrderByCreatedAtDesc(Users user); +} diff --git a/src/main/java/ssurent/ssurentbe/domain/users/repository/UserRepository.java b/src/main/java/ssurent/ssurentbe/domain/users/repository/UserRepository.java index 55e4541..b2826b1 100644 --- a/src/main/java/ssurent/ssurentbe/domain/users/repository/UserRepository.java +++ b/src/main/java/ssurent/ssurentbe/domain/users/repository/UserRepository.java @@ -10,4 +10,5 @@ public interface UserRepository extends JpaRepository { Optional findByStudentNum(String studentNum); boolean existsByStudentNum(String studentNum); + Optional findByStudentNumAndDeletedFalse(String studentNum); } diff --git a/src/main/java/ssurent/ssurentbe/domain/users/service/AuthService.java b/src/main/java/ssurent/ssurentbe/domain/users/service/AuthService.java index 3dfe655..dc03690 100644 --- a/src/main/java/ssurent/ssurentbe/domain/users/service/AuthService.java +++ b/src/main/java/ssurent/ssurentbe/domain/users/service/AuthService.java @@ -7,9 +7,9 @@ import ssurent.ssurentbe.common.exception.GeneralException; import ssurent.ssurentbe.common.jwt.JwtTokenProvider; import ssurent.ssurentbe.common.status.ErrorStatus; -import ssurent.ssurentbe.domain.users.dto.LoginRequest; -import ssurent.ssurentbe.domain.users.dto.SignupRequest; -import ssurent.ssurentbe.domain.users.dto.TokenResponse; +import ssurent.ssurentbe.domain.users.dto.request.LoginRequest; +import ssurent.ssurentbe.domain.users.dto.request.SignupRequest; +import ssurent.ssurentbe.domain.users.dto.response.TokenResponse; import ssurent.ssurentbe.domain.users.entity.Users; import ssurent.ssurentbe.domain.users.enums.Role; import ssurent.ssurentbe.domain.users.enums.Status; diff --git a/src/main/java/ssurent/ssurentbe/domain/users/service/UserCommandService.java b/src/main/java/ssurent/ssurentbe/domain/users/service/UserCommandService.java new file mode 100644 index 0000000..4360e83 --- /dev/null +++ b/src/main/java/ssurent/ssurentbe/domain/users/service/UserCommandService.java @@ -0,0 +1,27 @@ +package ssurent.ssurentbe.domain.users.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ssurent.ssurentbe.common.exception.GeneralException; +import ssurent.ssurentbe.common.status.ErrorStatus; +import ssurent.ssurentbe.domain.users.entity.Users; +import ssurent.ssurentbe.domain.users.repository.UserRepository; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UserCommandService { + private final UserRepository userRepository; + + public Users getUserInfo(String username) { + return userRepository.findByStudentNumAndDeletedFalse(username) + .orElseThrow(() -> new GeneralException(ErrorStatus.USER_NOT_FOUND)); + } + @Transactional + public void updatePhoneNumber(String username, String phoneNum) { + Users user = getUserInfo(username); + + user.updatePhoneNumber(phoneNum); + } +} diff --git a/src/main/java/ssurent/ssurentbe/domain/users/service/UserQueryService.java b/src/main/java/ssurent/ssurentbe/domain/users/service/UserQueryService.java new file mode 100644 index 0000000..e860322 --- /dev/null +++ b/src/main/java/ssurent/ssurentbe/domain/users/service/UserQueryService.java @@ -0,0 +1,42 @@ +package ssurent.ssurentbe.domain.users.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import ssurent.ssurentbe.common.exception.GeneralException; +import ssurent.ssurentbe.common.status.ErrorStatus; +import ssurent.ssurentbe.domain.users.dto.response.UserInfoResponse; +import ssurent.ssurentbe.domain.users.dto.response.UserPenaltyResponse; +import ssurent.ssurentbe.domain.users.entity.UserPenaltyLog; +import ssurent.ssurentbe.domain.users.entity.Users; +import ssurent.ssurentbe.domain.users.repository.UserPenaltyLogRepository; +import ssurent.ssurentbe.domain.users.repository.UserRepository; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class UserQueryService { + private final UserRepository userRepository; + private final UserPenaltyLogRepository userPenaltyLogRepository; + + public Users getUserInfo(String username) { + return userRepository.findByStudentNumAndDeletedFalse(username) + .orElseThrow(() -> new GeneralException(ErrorStatus.USER_NOT_FOUND)); + } + public UserInfoResponse getMyInfo(String username) { + Users user = getUserInfo(username); + return UserInfoResponse.from(user); + } + public List getMyPenalties(String username) { + Users user = getUserInfo(username); + + List logs = userPenaltyLogRepository.findByUserIdOrderByCreatedAtDesc(user); + + return logs.stream() + .map(UserPenaltyResponse::from) + .collect(Collectors.toList()); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 2d57f21..c81584b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,22 +1,21 @@ # Server server: - port: 8080 + port: 8080 # Profiles spring: - profiles: - active: prod + profiles: + active: prod # Swagger (Springdoc OpenAPI) springdoc: - api-docs: - path: /api-docs - swagger-ui: - path: /swagger-ui.html - operations-sorter: method - tagsSorter: alpha + api-docs: + path: /api-docs + swagger-ui: + path: /swagger-ui.html + operations-sorter: method # JWT jwt: - access-token-validity: 3600000 - refresh-token-validity: 604800000 \ No newline at end of file + access-token-validity: 3600000 + refresh-token-validity: 604800000 \ No newline at end of file