From 4cbb8386703b361cbc7f237fe13874837ab62cd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=98=88=EB=A6=BC?= <85860891+yerim216@users.noreply.github.com> Date: Thu, 30 May 2024 00:06:55 +0900 Subject: [PATCH] =?UTF-8?q?Feat:=20#10=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20request=20=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EC=88=98=EC=A0=95,=20User=20=EA=B4=80=EB=A0=A8=20A?= =?UTF-8?q?PI=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Feat: 회원가입/로그인 토큰 입력 Header->body로 변경, User 관련 api 제작 * Feat: User 엔티티 Wrapper Class로 수정, WebConfig 추가 * Feat: User 클래스 Getter 어노테이션 추가 --- .../domain/auth/AuthController.java | 16 ++--- .../nzgeneration/domain/auth/AuthService.java | 6 +- .../domain/auth/dto/AuthRequestDto.java | 11 ++++ .../nzgeneration/domain/user/User.java | 35 ++++++++-- .../domain/user/UserController.java | 53 ++++++++++++++- .../domain/user/UserRepository.java | 1 + .../nzgeneration/domain/user/UserService.java | 53 +++++++++++++++ .../domain/user/dto/UserResponseDto.java | 66 +++++++++++++++++++ .../response/code/status/ErrorStatus.java | 1 + .../nzgeneration/global/config/WebConfig.java | 19 ++++++ .../security/CurrentUserArgumentResolver.java | 4 +- .../global/utils/BaseTimeEntity.java | 2 + submodule | 2 +- 13 files changed, 247 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/example/nzgeneration/domain/user/dto/UserResponseDto.java create mode 100644 src/main/java/com/example/nzgeneration/global/config/WebConfig.java diff --git a/src/main/java/com/example/nzgeneration/domain/auth/AuthController.java b/src/main/java/com/example/nzgeneration/domain/auth/AuthController.java index 36fd8d8..c219d9a 100644 --- a/src/main/java/com/example/nzgeneration/domain/auth/AuthController.java +++ b/src/main/java/com/example/nzgeneration/domain/auth/AuthController.java @@ -1,6 +1,7 @@ package com.example.nzgeneration.domain.auth; import com.example.nzgeneration.domain.auth.dto.AuthRequestDto.CreateUserRequest; +import com.example.nzgeneration.domain.auth.dto.AuthRequestDto.UserIdTokenRequest; import com.example.nzgeneration.domain.auth.dto.AuthResponseDto.LoginSimpleInfo; import com.example.nzgeneration.domain.auth.enums.ResponseType; import com.example.nzgeneration.global.common.response.ApiResponse; @@ -9,7 +10,6 @@ import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -24,11 +24,8 @@ public class AuthController { @PostMapping("/login") @Operation(summary = "로그인/회원가입 api", description = "code : Authorization code / 회원가입, 로그인 구분 없이 동일한 API 사용") - public ApiResponse login(@RequestHeader("Authorization") String idToken){ - if (idToken != null && idToken.startsWith("Bearer ")) { - idToken = idToken.substring("Bearer ".length()); - } - LoginSimpleInfo loginSimpleInfo = authService.login(idToken); + public ApiResponse login(@RequestBody UserIdTokenRequest userTokenRequest){ + LoginSimpleInfo loginSimpleInfo = authService.login(userTokenRequest.getIdToken()); if(loginSimpleInfo.getResponseType()== ResponseType.SIGN_IN){ return ApiResponse.onSuccess(loginSimpleInfo); } @@ -37,11 +34,8 @@ public ApiResponse login(@RequestHeader("Authorization") String @PostMapping("/signup/extra") @Operation(summary = "회원가입 추가 정보 입력 api") - public ApiResponse signUp(@RequestHeader("Authorization") String token, @RequestBody CreateUserRequest createUserRequest){ - if (token != null && token.startsWith("Bearer ")) { - token = token.substring("Bearer ".length()); - } - return ApiResponse.onSuccess(authService.signUp(token, createUserRequest)); + public ApiResponse signUp(@RequestBody CreateUserRequest createUserRequest){ + return ApiResponse.onSuccess(authService.signUp(createUserRequest)); } @PostMapping("/refresh-token") diff --git a/src/main/java/com/example/nzgeneration/domain/auth/AuthService.java b/src/main/java/com/example/nzgeneration/domain/auth/AuthService.java index fe46768..88d41e2 100644 --- a/src/main/java/com/example/nzgeneration/domain/auth/AuthService.java +++ b/src/main/java/com/example/nzgeneration/domain/auth/AuthService.java @@ -39,15 +39,17 @@ public LoginSimpleInfo login(String idToken){ } @Transactional - public LoginSimpleInfo signUp(String token, CreateUserRequest createUserRequest){ - String email = jwtTokenProvider.validateTempTokenAndGetEmail(token); + public LoginSimpleInfo signUp(CreateUserRequest createUserRequest){ + String email = jwtTokenProvider.validateTempTokenAndGetEmail(createUserRequest.getToken()); if(userRepository.findByEmail(email).isPresent()) throw new GeneralException(ErrorStatus._DUPLICATE_USER); User user = User.toEntity(email, createUserRequest); + System.out.println("Saving user with badgeCount: " + user.getBadgeCount()); userRepository.save(user); String accessToken = jwtTokenProvider.createAccessToken(user.getPayload()); String refreshToken = jwtTokenProvider.createRefreshToken(user.getId()); user.updateToken(accessToken, refreshToken); + System.out.println("Saving user with badgeCount: " + user.getBadgeCount()); return LoginSimpleInfo.toDTO(accessToken, refreshToken, ResponseType.SIGN_IN); } diff --git a/src/main/java/com/example/nzgeneration/domain/auth/dto/AuthRequestDto.java b/src/main/java/com/example/nzgeneration/domain/auth/dto/AuthRequestDto.java index dbc5cb4..2051701 100644 --- a/src/main/java/com/example/nzgeneration/domain/auth/dto/AuthRequestDto.java +++ b/src/main/java/com/example/nzgeneration/domain/auth/dto/AuthRequestDto.java @@ -10,6 +10,7 @@ public class AuthRequestDto { @NoArgsConstructor @AllArgsConstructor public static class CreateUserRequest { + private String token; private String nickName; private String walletAddress; private String profileImgUrl; @@ -18,4 +19,14 @@ public static class CreateUserRequest { } + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class UserIdTokenRequest{ + private String idToken; + + } + + + } diff --git a/src/main/java/com/example/nzgeneration/domain/user/User.java b/src/main/java/com/example/nzgeneration/domain/user/User.java index fbb7b7d..f0c017f 100644 --- a/src/main/java/com/example/nzgeneration/domain/user/User.java +++ b/src/main/java/com/example/nzgeneration/domain/user/User.java @@ -8,6 +8,7 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import java.time.LocalDateTime; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -19,11 +20,11 @@ @AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) @Builder +@Getter public class User extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Getter private Long id; private String nickname; @@ -34,17 +35,22 @@ public class User extends BaseTimeEntity { private String walletAddress; - private int badgeCount; + private Integer badgeCount = 0; - private int cumulativePoint; + @ColumnDefault("0") + private Integer cumulativePoint = 0; - private int currentPoint; + @ColumnDefault("0") + private Integer currentPoint = 0; + + @ColumnDefault("0") + private Integer nftCount = 0; @ColumnDefault("true") - private boolean isAllowLocationInfo; + private Boolean isAllowLocationInfo; @ColumnDefault("true") - private boolean isAllowAdNotification; + private Boolean isAllowAdNotification; public void stamp(int point) { this.cumulativePoint += point; @@ -59,10 +65,26 @@ public void updateToken(String accessToken, String refreshToken){ this.refreshToken = refreshToken; } + public void updateNickName(String nickname){ + this.nickname = nickname; + } + + public void updateWalletAddress(String walletAddress){ + this.walletAddress = walletAddress; + } + + public void updateProfileImg(String imgUrl){ + this.profileImageUrl = imgUrl; + } + public String getPayload(){ return this.getId()+"+nz"; } + public LocalDateTime getCreatedAt(){ + return super.getCreatedAt(); + } + public static User toEntity(String email, CreateUserRequest createUserRequest){ return User.builder() .nickname(createUserRequest.getNickName()) @@ -74,6 +96,7 @@ public static User toEntity(String email, CreateUserRequest createUserRequest){ .badgeCount(0) .cumulativePoint(0) .currentPoint(0) + .nftCount(0) .build(); } } \ No newline at end of file diff --git a/src/main/java/com/example/nzgeneration/domain/user/UserController.java b/src/main/java/com/example/nzgeneration/domain/user/UserController.java index 3982dbb..3886ce8 100644 --- a/src/main/java/com/example/nzgeneration/domain/user/UserController.java +++ b/src/main/java/com/example/nzgeneration/domain/user/UserController.java @@ -1,21 +1,72 @@ package com.example.nzgeneration.domain.user; +import com.example.nzgeneration.domain.user.dto.UserResponseDto.UserEditingPageDetailInfo; +import com.example.nzgeneration.domain.user.dto.UserResponseDto.UserMyPageDetailInfo; +import com.example.nzgeneration.domain.user.dto.UserResponseDto.UserSigningSimpleInfo; import com.example.nzgeneration.global.common.response.ApiResponse; import com.example.nzgeneration.global.security.CurrentUser; +import io.swagger.v3.oas.annotations.Operation; import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; @RestController @RequiredArgsConstructor +@RequestMapping("/api/user") public class UserController { private final UserService userService; - @PostMapping("member/stamp") + @PostMapping("/stamp") public ApiResponse addStamp(@CurrentUser User user) { userService.addStamp(user); return ApiResponse.onSuccess("스탬프 찍기 성공"); } + @GetMapping("/check-nickname/{nickName}") + @Operation(summary = "닉네임 중복 확인", description = "true : 사용가능한 닉네임, false : 사용 불가능한 닉네임") + public ApiResponse checkNickName(@PathVariable String nickName){ + boolean status = userService.checkNickNameDuplicate(nickName); + return ApiResponse.onSuccess(status); + } + @PatchMapping("/nickname/{nickName}") + public ApiResponse updateNickName(@CurrentUser User user, @PathVariable String nickName){ + userService.updateNickName(user, nickName); + return ApiResponse.onSuccess("닉네임 수정 완료"); + + } + @PatchMapping("/wallet-address/{walletAddress}") + public ApiResponse updateWalletAddress(@CurrentUser User user, @PathVariable String walletAddress){ + userService.updateWalletAddress(user, walletAddress); + return ApiResponse.onSuccess("지갑 주소 수정 완료"); + } + @PatchMapping("/profile-image") + public ApiResponse updateProfileImg(@CurrentUser User user, @RequestPart MultipartFile image){ + userService.updateUserProfileImage(user, image); + return ApiResponse.onSuccess("프로필 사진 수정 완료"); + } + @GetMapping("/days-signing") + public ApiResponse getDaysSigning(@CurrentUser User user){ + return ApiResponse.onSuccess(userService.getDaysSigning(user)); + } + + @GetMapping("/my-page") + public ApiResponse getMyPageInfo(@CurrentUser User user){ + return ApiResponse.onSuccess(userService.getMyPageInfo(user)); + } + + @GetMapping("/edit-page") + public ApiResponse getEditPage(@CurrentUser User user){ + return ApiResponse.onSuccess(userService.getEditPageInfo(user)); + } + + + } diff --git a/src/main/java/com/example/nzgeneration/domain/user/UserRepository.java b/src/main/java/com/example/nzgeneration/domain/user/UserRepository.java index 6bba7b7..3236b36 100644 --- a/src/main/java/com/example/nzgeneration/domain/user/UserRepository.java +++ b/src/main/java/com/example/nzgeneration/domain/user/UserRepository.java @@ -6,4 +6,5 @@ public interface UserRepository extends JpaRepository { Optional findByEmail(String email); Optional findByRefreshToken(String token); + Optional findByNickname(String name); } \ No newline at end of file diff --git a/src/main/java/com/example/nzgeneration/domain/user/UserService.java b/src/main/java/com/example/nzgeneration/domain/user/UserService.java index 62528bf..4505749 100644 --- a/src/main/java/com/example/nzgeneration/domain/user/UserService.java +++ b/src/main/java/com/example/nzgeneration/domain/user/UserService.java @@ -1,16 +1,24 @@ package com.example.nzgeneration.domain.user; +import com.example.nzgeneration.domain.user.dto.UserResponseDto.UserEditingPageDetailInfo; +import com.example.nzgeneration.domain.user.dto.UserResponseDto.UserMyPageDetailInfo; +import com.example.nzgeneration.domain.user.dto.UserResponseDto.UserSigningSimpleInfo; import com.example.nzgeneration.global.common.response.code.status.ErrorStatus; import com.example.nzgeneration.global.common.response.exception.GeneralException; +import com.example.nzgeneration.global.s3.S3Service; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; @Service @RequiredArgsConstructor public class UserService { private final UserRepository userRepository; + private final S3Service s3Service; @Transactional public void addStamp(User user) { @@ -21,4 +29,49 @@ public void addStamp(User user) { //TODO - 포인트 상수, 기준 정하기 user.stamp(20); } + + @Transactional + public boolean checkNickNameDuplicate(String name){ + if(userRepository.findByNickname(name).isPresent()){ + return false; + } + return true; + } + + @Transactional + public void updateNickName(User user, String name){ + if(!checkNickNameDuplicate(name)){ + throw new GeneralException(ErrorStatus._DUPLICATE_NICKNAME); + } + user.updateNickName(name); + } + + @Transactional + public void updateWalletAddress(User user, String address){ + user.updateWalletAddress(address); + } + + @Transactional + public void updateUserProfileImage(User user, MultipartFile image){ + String profileImgUrl = s3Service.uploadFile(image).getImgUrl(); + user.updateProfileImg(profileImgUrl); + } + + public UserSigningSimpleInfo getDaysSigning(User user){ + LocalDateTime createdAt= user.getCreatedAt(); + LocalDateTime now = LocalDateTime.now(); + long daysBetween = ChronoUnit.DAYS.between(createdAt, now)+1; + return UserSigningSimpleInfo.toDTO(user, daysBetween); + } + + public UserMyPageDetailInfo getMyPageInfo(User user){ + return UserMyPageDetailInfo.toDTO(user); + } + + public UserEditingPageDetailInfo getEditPageInfo(User user){ + return UserEditingPageDetailInfo.toDTO(user); + } + + + } diff --git a/src/main/java/com/example/nzgeneration/domain/user/dto/UserResponseDto.java b/src/main/java/com/example/nzgeneration/domain/user/dto/UserResponseDto.java new file mode 100644 index 0000000..bba91d6 --- /dev/null +++ b/src/main/java/com/example/nzgeneration/domain/user/dto/UserResponseDto.java @@ -0,0 +1,66 @@ +package com.example.nzgeneration.domain.user.dto; + +import com.example.nzgeneration.domain.user.User; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class UserResponseDto { + @Builder + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class UserSigningSimpleInfo{ + private String nickName; + private long howManyDays; + + public static UserSigningSimpleInfo toDTO(User user, long days){ + return UserSigningSimpleInfo.builder() + .nickName(user.getNickname()) + .howManyDays(days) + .build(); + + } + } + + @Builder + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class UserMyPageDetailInfo{ + private String nickName; + private Integer currentPoint; + private Integer badgeCount; + private Integer nftCount; + + public static UserMyPageDetailInfo toDTO(User user){ + return UserMyPageDetailInfo.builder() + .nickName(user.getNickname()) + .badgeCount(user.getBadgeCount()) + .currentPoint(user.getCurrentPoint()) + .nftCount(user.getNftCount()) + .build(); + } + } + + @Builder + @Getter + @AllArgsConstructor + @NoArgsConstructor + public static class UserEditingPageDetailInfo{ + private String profileImgUrl; + private String nickName; + private String walletAddress; + + public static UserEditingPageDetailInfo toDTO(User user){ + return UserEditingPageDetailInfo.builder() + .profileImgUrl(user.getProfileImageUrl()) + .nickName(user.getNickname()) + .walletAddress(user.getWalletAddress()) + .build(); + } + + } + +} diff --git a/src/main/java/com/example/nzgeneration/global/common/response/code/status/ErrorStatus.java b/src/main/java/com/example/nzgeneration/global/common/response/code/status/ErrorStatus.java index 578ee83..f02771a 100644 --- a/src/main/java/com/example/nzgeneration/global/common/response/code/status/ErrorStatus.java +++ b/src/main/java/com/example/nzgeneration/global/common/response/code/status/ErrorStatus.java @@ -20,6 +20,7 @@ public enum ErrorStatus implements BaseErrorCode { _EMPTY_USER(HttpStatus.CONFLICT, 4001, "존재하지 않는 사용자입니다."), _INVALID_USER(HttpStatus.CONFLICT, 4002, "유효하지 않은 사용자입니다."), _DUPLICATE_USER(HttpStatus.CONFLICT, 4003, "이미 존재하는 사용자입니다"), + _DUPLICATE_NICKNAME(HttpStatus.CONFLICT, 4003, "이미 존재하는 닉네임입니다"), //인증 관련 _EMPTY_JWT(HttpStatus.UNAUTHORIZED, 4011, "JWT가 존재하지 않습니다."), diff --git a/src/main/java/com/example/nzgeneration/global/config/WebConfig.java b/src/main/java/com/example/nzgeneration/global/config/WebConfig.java new file mode 100644 index 0000000..455f171 --- /dev/null +++ b/src/main/java/com/example/nzgeneration/global/config/WebConfig.java @@ -0,0 +1,19 @@ +package com.example.nzgeneration.global.config; + +import com.example.nzgeneration.global.security.CurrentUserArgumentResolver; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + @Autowired + private CurrentUserArgumentResolver currentUserArgumentResolver; + + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(currentUserArgumentResolver); + } +} diff --git a/src/main/java/com/example/nzgeneration/global/security/CurrentUserArgumentResolver.java b/src/main/java/com/example/nzgeneration/global/security/CurrentUserArgumentResolver.java index 4c18aa0..0fa6812 100644 --- a/src/main/java/com/example/nzgeneration/global/security/CurrentUserArgumentResolver.java +++ b/src/main/java/com/example/nzgeneration/global/security/CurrentUserArgumentResolver.java @@ -8,12 +8,14 @@ import io.jsonwebtoken.Jwts; import lombok.RequiredArgsConstructor; import org.springframework.core.MethodParameter; +import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; @RequiredArgsConstructor +@Component public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver { private final JwtTokenProvider jwtTokenProvider; @@ -33,7 +35,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m String authorizationHeader = webRequest.getHeader("authorization"); if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { String token = authorizationHeader.substring(7); // "Bearer " 이후 문자열 - //return loadUserFromToken(token); + return loadUserFromToken(token); } throw new GeneralException(ErrorStatus._EMPTY_JWT); } diff --git a/src/main/java/com/example/nzgeneration/global/utils/BaseTimeEntity.java b/src/main/java/com/example/nzgeneration/global/utils/BaseTimeEntity.java index 356033d..7b4c45c 100644 --- a/src/main/java/com/example/nzgeneration/global/utils/BaseTimeEntity.java +++ b/src/main/java/com/example/nzgeneration/global/utils/BaseTimeEntity.java @@ -13,6 +13,7 @@ @MappedSuperclass @EntityListeners(AuditingEntityListener.class) public class BaseTimeEntity { + @Getter @CreatedDate @Column(name = "created_at") private LocalDateTime createdAt; @@ -20,4 +21,5 @@ public class BaseTimeEntity { @LastModifiedDate @Column(name = "updated_at") private LocalDateTime updatedAt; + } \ No newline at end of file diff --git a/submodule b/submodule index 98ff590..4e1a14a 160000 --- a/submodule +++ b/submodule @@ -1 +1 @@ -Subproject commit 98ff590c67504388e79263596e9cc3e921284203 +Subproject commit 4e1a14adc1ba500d17eee6d0ab9cac327ff17f02