Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIX/#82] 이미 인증된 동네가 존재할 때 동네 인증 재진행 시 예외 처리 추가 #83

Merged
merged 6 commits into from
Feb 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public enum ErrorType {
INVALID_FAVORITE_SPOT_ERROR(HttpStatus.BAD_REQUEST, 40017, "유효하지 않은 favoriteSpot입니다."),
INVALID_FAVORITE_SPOT_RANK_SIZE_ERROR(HttpStatus.BAD_REQUEST, 40030, "favoriteSpotRank의 사이즈가 잘못되었습니다."),
INVALID_FAVORITE_CUISINE_RANK_SIZE_ERROR(HttpStatus.BAD_REQUEST, 40031, "favoriteCuisineRank의 사이즈가 잘못되었습니다."),
ALREADY_VERIFIED_AREA_ERROR(HttpStatus.BAD_REQUEST, 40032, "이미 인증된 동네가 존재합니다."),
INVALID_IMAGE_TYPE_ERROR(HttpStatus.BAD_REQUEST, 40045, "유효하지 않은 imageType입니다."),

/* 500 Internal Server Error */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.acon.server.member.api.request.ReissueTokenRequest;
import com.acon.server.member.api.request.WithdrawalReasonRequest;
import com.acon.server.member.api.response.AcornCountResponse;
import com.acon.server.member.api.response.AreaResponse;
import com.acon.server.member.api.response.LoginResponse;
import com.acon.server.member.api.response.MemberAreaResponse;
import com.acon.server.member.api.response.PreSignedUrlResponse;
Expand Down Expand Up @@ -65,13 +66,14 @@ public ResponseEntity<LoginResponse> login(
public ResponseEntity<MemberAreaResponse> postArea(
@Valid @RequestBody final MemberAreaRequest request
) {
String area = memberService.createMemberArea(request.latitude(), request.longitude());

return ResponseEntity.ok(new MemberAreaResponse(area));
return ResponseEntity.ok(
memberService.createMemberArea(request.latitude(), request.longitude())
);
}

@GetMapping(path = "/area", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<MemberAreaResponse> getArea(
public ResponseEntity<AreaResponse> getArea(
@DecimalMin(value = "33.1", message = "위도는 최소 33.1°N 이상이어야 합니다.(대한민국 기준)")
@DecimalMax(value = "38.6", message = "위도는 최대 38.6°N 이하이어야 합니다.(대한민국 기준)")
@Validated @RequestParam(name = "latitude") final Double latitude,
Expand All @@ -81,7 +83,7 @@ public ResponseEntity<MemberAreaResponse> getArea(
) {
String area = memberService.fetchMemberArea(latitude, longitude);

return ResponseEntity.ok(new MemberAreaResponse(area));
return ResponseEntity.ok(new AreaResponse(area));
}

@PostMapping(path = "/member/preference", consumes = MediaType.APPLICATION_JSON_VALUE)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.acon.server.member.api.response;

public record AreaResponse(
String area
) {

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

public record LoginResponse(
String accessToken,
String refreshToken
String refreshToken,
boolean hasVerifiedArea
) {

public static LoginResponse of(
final String accessToken,
final String refreshToken
final String refreshToken,
final boolean hasVerifiedArea
) {
return new LoginResponse(accessToken, refreshToken);
return new LoginResponse(accessToken, refreshToken, hasVerifiedArea);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
package com.acon.server.member.api.response;

public record MemberAreaResponse(
String area
Long id,
String name
) {

public static MemberAreaResponse of(
final Long id,
final String name
) {
return new MemberAreaResponse(id, name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.acon.server.global.external.s3.S3Adapter;
import com.acon.server.member.api.response.AcornCountResponse;
import com.acon.server.member.api.response.LoginResponse;
import com.acon.server.member.api.response.MemberAreaResponse;
import com.acon.server.member.api.response.PreSignedUrlResponse;
import com.acon.server.member.api.response.ProfileResponse;
import com.acon.server.member.api.response.ReissueTokenResponse;
Expand Down Expand Up @@ -99,7 +100,9 @@ public LoginResponse login(
String accessToken = jwtTokenProvider.issueAccessToken(memberAuthentication);
String refreshToken = jwtTokenProvider.issueRefreshToken(memberId);

return LoginResponse.of(accessToken, refreshToken);
boolean hasVerifiedArea = verifiedAreaRepository.existsByMemberId(memberId);

return LoginResponse.of(accessToken, refreshToken, hasVerifiedArea);
}

protected Long fetchMemberId(
Expand All @@ -126,31 +129,43 @@ protected Long fetchMemberId(
}

@Transactional
public String createMemberArea(
public MemberAreaResponse createMemberArea(
final Double latitude,
final Double longitude
) {
MemberEntity memberEntity = memberRepository.findByIdOrElseThrow(principalHandler.getUserIdFromPrincipal());

// 추후 여러 동네 인증이 가능하게 되면 제거 예정
if (verifiedAreaRepository.existsByMemberId(memberEntity.getId())) {
throw new BusinessException(ErrorType.ALREADY_VERIFIED_AREA_ERROR);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q2:

요거 추후 한 동네에 대한 재인증 로직이 추가되면 어떻게 수정할 예정이신가요 ?!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아마 그런 로직이 추가될 때쯤 원래 기획대로 여러 동네 인증이 가능하지 않을까 싶어요!
일단 한 동네에 대한 재인증 로직만 추가된다고 가정했을 때는 아래 플로우로 갈 것 같습니다~

  • 동네 인증을 한 번도 안했으면 create
  • 해당 동에 인증을 한 사용자면 날짜 업데이트,
  • 다른 동에 이미 인증을 한 사용자면 에러


String legalDong = naverMapsAdapter.getReverseGeoCodingResult(latitude, longitude);
Optional<VerifiedAreaEntity> optionalVerifiedAreaEntity = verifiedAreaRepository.findByMemberIdAndName(
memberEntity.getId(), legalDong);

optionalVerifiedAreaEntity.ifPresentOrElse(
verifiedAreaEntity -> {
VerifiedArea verifiedArea = verifiedAreaMapper.toDomain(verifiedAreaEntity);
verifiedArea.updateVerifiedDate(LocalDate.now());
verifiedAreaRepository.save(verifiedAreaMapper.toEntity(verifiedArea));
},
() -> verifiedAreaRepository.save(
VerifiedAreaEntity.builder()
.name(legalDong)
.memberId(memberEntity.getId())
.verifiedDate(Collections.singletonList(LocalDate.now()))
.build()
)
);
LocalDate currentDate = LocalDate.now();
VerifiedAreaEntity savedVerifiedAreaEntity = optionalVerifiedAreaEntity
.map(entity -> updateVerifiedAreaEntity(entity, currentDate))
.orElseGet(() -> createVerifiedAreaEntity(legalDong, memberEntity.getId(), currentDate));

return MemberAreaResponse.of(savedVerifiedAreaEntity.getId(), savedVerifiedAreaEntity.getName());
}

return legalDong;
private VerifiedAreaEntity updateVerifiedAreaEntity(VerifiedAreaEntity entity, LocalDate currentDate) {
VerifiedArea verifiedArea = verifiedAreaMapper.toDomain(entity);
verifiedArea.updateVerifiedDate(currentDate);
return verifiedAreaRepository.save(verifiedAreaMapper.toEntity(verifiedArea));
}

private VerifiedAreaEntity createVerifiedAreaEntity(String legalDong, Long memberId, LocalDate currentDate) {
return verifiedAreaRepository.save(
VerifiedAreaEntity.builder()
.name(legalDong)
.memberId(memberId)
.verifiedDate(Collections.singletonList(currentDate))
.build()
);
}

@Transactional(readOnly = true)
Expand Down Expand Up @@ -280,6 +295,7 @@ public ReissueTokenResponse reissueToken(String refreshToken) {
public void withdrawMember(String reason, String refreshToken) {
MemberEntity memberEntity = memberRepository.findByIdOrElseThrow(principalHandler.getUserIdFromPrincipal());

// TODO: memberId 존재하는 테이블에 member row 제거 ( 리뷰 테이블 제외 )
memberRepository.deleteById(memberEntity.getId());
jwtTokenProvider.deleteRefreshToken(refreshToken);
// TODO: 엑세스 토큰 블랙리스트
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ public interface VerifiedAreaRepository extends JpaRepository<VerifiedAreaEntity
Optional<VerifiedAreaEntity> findByMemberIdAndName(Long memberId, String name);

List<VerifiedAreaEntity> findAllByMemberId(Long memberId);

boolean existsByMemberId(Long memberId);
}