Skip to content

Commit

Permalink
fix: ✏️ 사용자 로그 관리 정책 변경에 따른 Device API 수정 (#104)
Browse files Browse the repository at this point in the history
* fix: 배포 파이프라인 이미지 빌드 버전 추가

* fix: device entity os & model 필드 제거

* fix: device token dto model, os 필드 제거

* fix: device_dto to_entity() 메서드 복구

* fix: device update 메서드 호출 시, activate 상태로 변경

* fix: device 등록 비지니스 로직 수정

* test: device controller unit test에서 model, os 제거

* fix: device_fixture model, os 필드 제거

* rename: fixture token 변경 상수명 수정

* fix: device entity 조회 시 활성화 조건 추가

* fix: device usecase 테스트 시나리오 수정

* fix: device 쿼리 자동 조건문 수정

* test: origin_token에 대한 정보가 없는 경우 new_token 등록

* fix: @sql_restriction 제거

* test: 수정 요청 & 기존 토큰 없을 시, 수정 토큰으로 신규 등록 테스트

* fix: device_register_service 로직 수정

* fix: device_dto new_token 필드 제거

* test: device controller unit test 수정

* fix: device 응답 객체 생성 시 요청 토큰이 아닌 서버 토큰을 응답으로 사용

* fix: device_register_service 제거 && 로직 단순화

* fix: 사용자가 보낸 토큰이 서버에서 비활성화 상태일 때 예외처리

* test: test case 요청 수정

* rename: device -> device_token으로 수정

* rename: device_token entity to_string 수정

* rename: device token put 요청 응답 key 수정

* docs: device put api 스웨거 수정

* fix: device controller 경로 수정

* test: device_token controller unit test 변경된 url 및 응답 포맷 반영

* test: device_fixture -> device_token_fixture

* test: 단일 token에 대한 시나리오로 테스트 수정 및 비활성화 토큰 요청 에러 케이스 추가

* fix: register_device_token 파사드 패턴 적용

* fix: device_token_unregister 파사드 패턴 적용

* test: device token 단위 테스트 분리

* test: device_token_unregister_service_test 분리

* fix: user_account_use_case 파사드 패턴 적용

* test: user_account_usecase unit test 분리

* fix: device entity os & model 필드 제거

* fix: device token dto model, os 필드 제거

* fix: device_dto to_entity() 메서드 복구

* fix: device update 메서드 호출 시, activate 상태로 변경

* fix: device 등록 비지니스 로직 수정

* test: device controller unit test에서 model, os 제거

* fix: device_fixture model, os 필드 제거

* rename: fixture token 변경 상수명 수정

* fix: device entity 조회 시 활성화 조건 추가

* fix: device usecase 테스트 시나리오 수정

* fix: device 쿼리 자동 조건문 수정

* test: origin_token에 대한 정보가 없는 경우 new_token 등록

* fix: @sql_restriction 제거

* test: 수정 요청 & 기존 토큰 없을 시, 수정 토큰으로 신규 등록 테스트

* fix: device_register_service 로직 수정

* fix: device_dto new_token 필드 제거

* test: device controller unit test 수정

* fix: device 응답 객체 생성 시 요청 토큰이 아닌 서버 토큰을 응답으로 사용

* fix: device_register_service 제거 && 로직 단순화

* fix: 사용자가 보낸 토큰이 서버에서 비활성화 상태일 때 예외처리

* test: test case 요청 수정

* rename: device -> device_token으로 수정

* rename: device_token entity to_string 수정

* rename: device token put 요청 응답 key 수정

* docs: device put api 스웨거 수정

* fix: device controller 경로 수정

* test: device_token controller unit test 변경된 url 및 응답 포맷 반영

* test: device_fixture -> device_token_fixture

* test: 단일 token에 대한 시나리오로 테스트 수정 및 비활성화 토큰 요청 에러 케이스 추가

* fix: register_device_token 파사드 패턴 적용

* fix: device_token_unregister 파사드 패턴 적용

* test: device token 단위 테스트 분리

* test: device_token_unregister_service_test 분리

* fix: user_account_use_case 파사드 패턴 적용

* test: user_account_usecase unit test 분리

* fix: user_profile_update_dto merge conflict
  • Loading branch information
psychology50 authored Jun 5, 2024
1 parent 35710d0 commit 772b23f
Show file tree
Hide file tree
Showing 33 changed files with 1,003 additions and 955 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotBlank;
import kr.co.pennyway.api.apis.users.dto.DeviceDto;
import kr.co.pennyway.api.apis.users.dto.DeviceTokenDto;
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;
Expand All @@ -24,15 +24,14 @@

@Tag(name = "사용자 계정 관리 API", description = "사용자 본인의 계정 관리를 위한 Usecase를 제공합니다.")
public interface UserAccountApi {
@Operation(summary = "디바이스 등록", description = "사용자의 디바이스 정보를 등록(originToken == newToken)하거나 갱신(originToken != newToken)합니다.")
@Operation(summary = "디바이스 등록", description = "사용자의 디바이스 정보를 등록합니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", content = @Content(mediaType = "application/json", examples = {
@ExampleObject(name = "디바이스 등록 성공", value = """
@ApiResponse(responseCode = "200", content = @Content(mediaType = "application/json", schemaProperties = @SchemaProperty(name = "deviceToken", schema = @Schema(implementation = DeviceTokenDto.RegisterRes.class)))),
@ApiResponse(responseCode = "400", content = @Content(mediaType = "application/json", examples = {
@ExampleObject(name = "잘못된 디바이스 토큰 저장 요청", description = "서버에 동일한 이름의 토큰이 사용자에게 등록되어 있고, 해당 토큰이 만료처리되어 있을 경우에 해당한다. (애초에 발생해선 안 되는 에러)", value = """
{
"device": {
"id": 1,
"token": "newToken"
}
"code": "4005",
"message": "활성화되지 않은 디바이스 토큰 정보입니다."
}
""")
})),
Expand All @@ -45,7 +44,7 @@ public interface UserAccountApi {
""")
}))
})
ResponseEntity<?> putDevice(@RequestBody @Validated DeviceDto.RegisterReq request, @AuthenticationPrincipal SecurityUserDetails user);
ResponseEntity<?> putDevice(@RequestBody @Validated DeviceTokenDto.RegisterReq request, @AuthenticationPrincipal SecurityUserDetails user);

@Operation(summary = "디바이스 토큰 제거", description = "사용자의 디바이스 정보와 토큰을 제거합니다.")
@Parameter(name = "token", description = "삭제할 디바이스 토큰", required = true, in = ParameterIn.QUERY)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,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.DeviceTokenDto;
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;
Expand All @@ -24,17 +24,17 @@ public class UserAccountController implements UserAccountApi {
private final UserAccountUseCase userAccountUseCase;

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

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

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package kr.co.pennyway.api.apis.users.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import kr.co.pennyway.domain.domains.device.domain.DeviceToken;
import kr.co.pennyway.domain.domains.user.domain.User;

public class DeviceTokenDto {
@Schema(title = "디바이스 등록 요청")
public record RegisterReq(
@Schema(description = "디바이스 FCM 토큰", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "token은 필수입니다.")
String token
) {
public DeviceToken toEntity(User user) {
return DeviceToken.of(token, user);
}
}

@Schema(title = "디바이스 등록 응답")
public record RegisterRes(
@Schema(title = "디바이스 ID")
Long id,
@Schema(title = "디바이스 토큰")
String token
) {
public static RegisterRes of(Long id, String token) {
return new RegisterRes(id, token);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import kr.co.pennyway.api.common.validator.Password;
import kr.co.pennyway.domain.domains.user.domain.NotifySetting;

public class UserProfileUpdateDto {
@Schema(title = "이름 변경 요청 DTO")
Expand Down Expand Up @@ -47,7 +46,7 @@ public record PasswordReq(
}

@Schema(title = "사용자 알림 설정 응답 DTO")
public record NotifySettingUpdateReq(
public record NotifySettingUpdateRes(
@Schema(description = "계좌 알림 설정", example = "true", requiredMode = Schema.RequiredMode.NOT_REQUIRED)
@JsonInclude(JsonInclude.Include.NON_NULL)
Boolean accountBookNotify,
Expand All @@ -58,13 +57,6 @@ public record NotifySettingUpdateReq(
@JsonInclude(JsonInclude.Include.NON_NULL)
Boolean chatNotify
) {
public static NotifySettingUpdateReq of(NotifySetting.NotifyType type, Boolean flag) {
return switch (type) {
case ACCOUNT_BOOK -> new NotifySettingUpdateReq(flag, null, null);
case FEED -> new NotifySettingUpdateReq(null, flag, null);
case CHAT -> new NotifySettingUpdateReq(null, null, flag);
};
}
}

@Schema(title = "프로필 이미지 등록 요청 DTO")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package kr.co.pennyway.api.apis.users.mapper;

import kr.co.pennyway.api.apis.users.dto.DeviceTokenDto;
import kr.co.pennyway.common.annotation.Mapper;
import kr.co.pennyway.domain.domains.device.domain.DeviceToken;

@Mapper
public class DeviceTokenMapper {
public static DeviceTokenDto.RegisterRes toRegisterRes(DeviceToken deviceToken) {
return DeviceTokenDto.RegisterRes.of(deviceToken.getId(), deviceToken.getToken());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import kr.co.pennyway.api.apis.users.dto.OauthAccountDto;
import kr.co.pennyway.api.apis.users.dto.UserProfileDto;
import kr.co.pennyway.api.apis.users.dto.UserProfileUpdateDto;
import kr.co.pennyway.common.annotation.Mapper;
import kr.co.pennyway.domain.domains.oauth.domain.Oauth;
import kr.co.pennyway.domain.domains.user.domain.NotifySetting;
import kr.co.pennyway.domain.domains.user.domain.User;

import java.util.Set;
Expand All @@ -24,4 +26,12 @@ public static UserProfileDto toUserProfileDto(User user, Set<Oauth> oauths) {

return UserProfileDto.from(user, OauthAccountDto.of(kakao, google, apple));
}

public static UserProfileUpdateDto.NotifySettingUpdateRes toNotifySettingUpdateRes(NotifySetting.NotifyType type, Boolean flag) {
return switch (type) {
case ACCOUNT_BOOK -> new UserProfileUpdateDto.NotifySettingUpdateRes(flag, null, null);
case FEED -> new UserProfileUpdateDto.NotifySettingUpdateRes(null, flag, null);
case CHAT -> new UserProfileUpdateDto.NotifySettingUpdateRes(null, null, flag);
};
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package kr.co.pennyway.api.apis.users.service;

import kr.co.pennyway.domain.domains.device.domain.DeviceToken;
import kr.co.pennyway.domain.domains.device.exception.DeviceTokenErrorCode;
import kr.co.pennyway.domain.domains.device.exception.DeviceTokenErrorException;
import kr.co.pennyway.domain.domains.device.service.DeviceTokenService;
import kr.co.pennyway.domain.domains.user.domain.User;
import kr.co.pennyway.domain.domains.user.exception.UserErrorCode;
import kr.co.pennyway.domain.domains.user.exception.UserErrorException;
import kr.co.pennyway.domain.domains.user.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceTokenRegisterService {
private final UserService userService;
private final DeviceTokenService deviceTokenService;

@Transactional
public DeviceToken execute(Long userId, String token) {
User user = userService.readUser(userId).orElseThrow(() -> new UserErrorException(UserErrorCode.NOT_FOUND));
DeviceToken deviceToken = getOrCreateDevice(user, token);

if (!deviceToken.isActivated()) {
throw new DeviceTokenErrorException(DeviceTokenErrorCode.NOT_ACTIVATED_DEVICE);
}

return deviceToken;
}

private DeviceToken getOrCreateDevice(User user, String token) {
return deviceTokenService.readDeviceByUserIdAndToken(user.getId(), token)
.orElseGet(() -> deviceTokenService.createDevice(DeviceToken.of(token, user)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package kr.co.pennyway.api.apis.users.service;

import kr.co.pennyway.domain.domains.device.domain.DeviceToken;
import kr.co.pennyway.domain.domains.device.exception.DeviceTokenErrorCode;
import kr.co.pennyway.domain.domains.device.exception.DeviceTokenErrorException;
import kr.co.pennyway.domain.domains.device.service.DeviceTokenService;
import kr.co.pennyway.domain.domains.user.domain.User;
import kr.co.pennyway.domain.domains.user.exception.UserErrorCode;
import kr.co.pennyway.domain.domains.user.exception.UserErrorException;
import kr.co.pennyway.domain.domains.user.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceTokenUnregisterService {
private final UserService userService;
private final DeviceTokenService deviceTokenService;

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

DeviceToken deviceToken = deviceTokenService.readDeviceByUserIdAndToken(user.getId(), token).orElseThrow(
() -> new DeviceTokenErrorException(DeviceTokenErrorCode.NOT_FOUND_DEVICE)
);

deviceTokenService.deleteDevice(deviceToken);
}
}
Loading

0 comments on commit 772b23f

Please sign in to comment.