Skip to content

Commit

Permalink
✨ 사용자 아이디/이름 수정 API (#59)
Browse files Browse the repository at this point in the history
* test: 사용자 계정 api 내부 클래스로 분리

* test: 사용자 이름 수정 controller unit pre-condition 작성

* test: 이름 수정 요청 controller unit test case 작성

* fix: 일반 회원가입 계정이 아닌 예외 상수 추가 : 4004

* feat: 이름 변경 요청 dto 정의

* feat: put_name() controller 메서드 추가

* feat: update_name() usecase 추가 및 void 타입에 맞게 테스트 코드 given 수정

* test: 422 예상 에러 코드 수정

* test: 사용자 계정 usecase 기존 test 내부 클래스로 분리

* test: 일반 회원가입 유저 pre-condition 제거

* test: 이름 수정 usecase test case 작성

* feat: 사용자 이름 수정 로직 구현

* feat: user 도메인 이름 수정 메서드 추가

* test: user_account_use_case_test 순서 지정

* fix: 디바이스 비활성화 em.create_query() -> 메서드 호출 (기존 방식 에러 발생)

* test: 사용자 닉네임 수정 controller unit test 작성

* feat: 사용자 아이디 변경 요청 dto 작성

* feat: 사용자 아이디 변경 요청 api 작성

* feat: 사용자 아이디 변경 요청 usecase 작성

* feat: 사용자 아이디 변경 service 로직 구현

* test: nickname -> username

* test: 테스트 코드에서 entitymanager 주입 제거

* refactor: user account use case 사용자 조회 메서드 분리

* fix: 이름 및 아이디 수정 요청 메서드 put -> patch

* test: put 요청 patch로 변경
  • Loading branch information
psychology50 authored Apr 26, 2024
1 parent f000034 commit b267155
Show file tree
Hide file tree
Showing 9 changed files with 545 additions and 226 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import jakarta.validation.constraints.NotBlank;
import kr.co.pennyway.api.apis.users.dto.DeviceDto;
import kr.co.pennyway.api.apis.users.dto.UserProfileDto;
import kr.co.pennyway.api.apis.users.dto.UserProfileUpdateDto;
import kr.co.pennyway.api.common.security.authentication.SecurityUserDetails;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
Expand Down Expand Up @@ -60,4 +61,10 @@ public interface UserAccountApi {
@Operation(summary = "사용자 계정 조회", description = "사용자 본인의 계정 정보를 조회합니다.")
@ApiResponse(responseCode = "200", content = @Content(schemaProperties = @SchemaProperty(name = "user", schema = @Schema(implementation = UserProfileDto.class))))
ResponseEntity<?> getMyAccount(@AuthenticationPrincipal SecurityUserDetails user);

@Operation(summary = "사용자 이름 수정")
ResponseEntity<?> putName(@RequestBody @Validated UserProfileUpdateDto.NameReq request, @AuthenticationPrincipal SecurityUserDetails user);

@Operation(summary = "사용자 아이디 수정")
ResponseEntity<?> putUsername(@RequestBody @Validated UserProfileUpdateDto.UsernameReq request, @AuthenticationPrincipal SecurityUserDetails user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.validation.constraints.NotBlank;
import kr.co.pennyway.api.apis.users.api.UserAccountApi;
import kr.co.pennyway.api.apis.users.dto.DeviceDto;
import kr.co.pennyway.api.apis.users.dto.UserProfileUpdateDto;
import kr.co.pennyway.api.apis.users.usecase.UserAccountUseCase;
import kr.co.pennyway.api.common.response.SuccessResponse;
import kr.co.pennyway.api.common.security.authentication.SecurityUserDetails;
Expand All @@ -21,22 +22,41 @@
public class UserAccountController implements UserAccountApi {
private final UserAccountUseCase userAccountUseCase;

@Override
@PutMapping("/devices")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<?> putDevice(@RequestBody @Validated DeviceDto.RegisterReq request, @AuthenticationPrincipal SecurityUserDetails user) {
return ResponseEntity.ok(SuccessResponse.from("device", userAccountUseCase.registerDevice(user.getUserId(), request)));
}

@Override
@DeleteMapping("/devices")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<?> deleteDevice(@RequestParam("token") @Validated @NotBlank String token, @AuthenticationPrincipal SecurityUserDetails user) {
userAccountUseCase.unregisterDevice(user.getUserId(), token);
return ResponseEntity.ok(SuccessResponse.noContent());
}

@Override
@GetMapping("")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<?> getMyAccount(@AuthenticationPrincipal SecurityUserDetails user) {
return ResponseEntity.ok(SuccessResponse.from("user", userAccountUseCase.getMyAccount(user.getUserId())));
}

@Override
@PatchMapping("/name")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<?> putName(UserProfileUpdateDto.NameReq request, SecurityUserDetails user) {
userAccountUseCase.updateName(user.getUserId(), request.name());
return ResponseEntity.ok(SuccessResponse.noContent());
}

@Override
@PatchMapping("/username")
@PreAuthorize("isAuthenticated()")
public ResponseEntity<?> putUsername(UserProfileUpdateDto.UsernameReq request, SecurityUserDetails user) {
userAccountUseCase.updateUsername(user.getUserId(), request.username());
return ResponseEntity.ok(SuccessResponse.noContent());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package kr.co.pennyway.api.apis.users.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;

public class UserProfileUpdateDto {
@Schema(title = "이름 변경 요청 DTO")
public record NameReq(
@Schema(description = "이름", example = "페니웨이")
@NotBlank(message = "이름을 입력해주세요")
@Pattern(regexp = "^[가-힣a-z]{2,8}$", message = "2~8자의 한글, 영문 소문자만 사용 가능합니다.")
String name
) {
}

@Schema(title = "아이디 변경 요청 DTO")
public record UsernameReq(
@Schema(description = "아이디", example = "pennyway")
@NotBlank(message = "아이디를 입력해주세요")
@Pattern(regexp = "^[a-z-_.]{5,20}$", message = "5~20자의 영문 소문자, -, _, . 만 사용 가능합니다.")
String username
) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package kr.co.pennyway.api.apis.users.service;

import kr.co.pennyway.domain.domains.user.domain.User;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserProfileUpdateService {
@Transactional
public void updateName(User user, String newName) {
user.updateName(newName);
}

@Transactional
public void updateUsername(User user, String newUsername) {
user.updateUsername(newUsername);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import kr.co.pennyway.api.apis.users.dto.DeviceDto;
import kr.co.pennyway.api.apis.users.dto.UserProfileDto;
import kr.co.pennyway.api.apis.users.service.DeviceRegisterService;
import kr.co.pennyway.api.apis.users.service.UserProfileUpdateService;
import kr.co.pennyway.common.annotation.UseCase;
import kr.co.pennyway.domain.domains.device.domain.Device;
import kr.co.pennyway.domain.domains.device.exception.DeviceErrorCode;
Expand All @@ -23,13 +24,13 @@ public class UserAccountUseCase {
private final UserService userService;
private final DeviceService deviceService;

private final UserProfileUpdateService userProfileUpdateService;

private final DeviceRegisterService deviceRegisterService;

@Transactional
public DeviceDto.RegisterRes registerDevice(Long userId, DeviceDto.RegisterReq request) {
User user = userService.readUser(userId).orElseThrow(
() -> new UserErrorException(UserErrorCode.NOT_FOUND)
);
User user = readUserOrThrow(userId);

Device device = deviceRegisterService.createOrUpdateDevice(user, request);

Expand All @@ -38,9 +39,7 @@ public DeviceDto.RegisterRes registerDevice(Long userId, DeviceDto.RegisterReq r

@Transactional
public void unregisterDevice(Long userId, String token) {
User user = userService.readUser(userId).orElseThrow(
() -> new UserErrorException(UserErrorCode.NOT_FOUND)
);
User user = readUserOrThrow(userId);

Device device = deviceService.readDeviceByUserIdAndToken(user.getId(), token).orElseThrow(
() -> new DeviceErrorException(DeviceErrorCode.NOT_FOUND_DEVICE)
Expand All @@ -51,10 +50,28 @@ public void unregisterDevice(Long userId, String token) {

@Transactional(readOnly = true)
public UserProfileDto getMyAccount(Long userId) {
User user = userService.readUser(userId).orElseThrow(
() -> new UserErrorException(UserErrorCode.NOT_FOUND)
);
User user = readUserOrThrow(userId);

return UserProfileDto.from(user);
}

@Transactional
public void updateName(Long userId, String newName) {
User user = readUserOrThrow(userId);

userProfileUpdateService.updateName(user, newName);
}

@Transactional
public void updateUsername(Long userId, String newUsername) {
User user = readUserOrThrow(userId);

userProfileUpdateService.updateUsername(user, newUsername);
}

private User readUserOrThrow(Long userId) {
return userService.readUser(userId).orElseThrow(
() -> new UserErrorException(UserErrorCode.NOT_FOUND)
);
}
}
Loading

0 comments on commit b267155

Please sign in to comment.