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

[FEAT-150] 계좌 인증 및 어뷰징 유저 확인 추가 #152

Merged
merged 24 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
bbfe881
[FEAT] 계좌 연동 실패 엔티티 설계
wlwpfh Dec 11, 2023
ee61003
[FEAT] 어뷰징 관련 레포지토리 설정
wlwpfh Dec 11, 2023
63836c6
[FEAT] 어뷰징 에러 설정
wlwpfh Dec 11, 2023
89895fc
[FEAT] 어뷰징 에러 메시지 설정
wlwpfh Dec 11, 2023
8ef0b74
[FEAT] 어뷰징 유저인 경우 예외처리
wlwpfh Dec 11, 2023
b084062
[FEAT] 어뷰징 유저가 아닌 경우 응답 설정
wlwpfh Dec 11, 2023
0cb81b8
[FEAT] 어뷰징 빌더 설정
wlwpfh Dec 11, 2023
d04e86d
[FEAT] 어뷰징 횟수 세기 설정
wlwpfh Dec 11, 2023
9e0a071
[FEAT] 빌더 어노테이션 제거
wlwpfh Dec 11, 2023
0370151
[FEAT] 어뷰징 유저 조회 수정
wlwpfh Dec 11, 2023
f3e36cf
[FIX] 테스트 파라미터 추가
wlwpfh Dec 11, 2023
f5cb9b8
[FIX] 쿼리 칼럼명 수정
wlwpfh Dec 11, 2023
c3362aa
[FIX] request body 설정
wlwpfh Dec 11, 2023
a6ed9e2
[FIX] transactional 설정
wlwpfh Dec 11, 2023
15ce477
[ADD] 실패 응답에 데이터 추가
wlwpfh Dec 13, 2023
3e1e936
[ADD] entitylistener 어노테이션 추가
wlwpfh Dec 13, 2023
2b259e6
[ADD] 어뷰징 유저는 소원 생성 불가
wlwpfh Dec 13, 2023
80553c5
[FIX] 계좌 인증 로직 수정
wlwpfh Dec 13, 2023
e99253e
[TEST] 테스트 수정
wlwpfh Dec 13, 2023
15cd79e
[ADD] dto jsonproperty 수정
wlwpfh Dec 13, 2023
179122e
[CHORE] 코드 정렬
wlwpfh Dec 13, 2023
0becd8c
[FIX] 코드리뷰 반영
wlwpfh Dec 13, 2023
a4109a7
[FIX] 순환참조 수정
wlwpfh Dec 13, 2023
1a212cc
[CHORE] 사용하지 않는 import 삭제
wlwpfh Dec 13, 2023
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
10 changes: 10 additions & 0 deletions src/main/java/com/sopterm/makeawish/common/AbuseException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.sopterm.makeawish.common;

import lombok.Getter;

@Getter
public class AbuseException extends RuntimeException {
public AbuseException(String message) {
super(message);
}
}
8 changes: 8 additions & 0 deletions src/main/java/com/sopterm/makeawish/common/ApiResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,12 @@ public static ApiResponse fail(String message) {
.message(message)
.build();
}

public static ApiResponse fail(String message, Object data) {
return ApiResponse.builder()
.success(false)
.message(message)
.data(data)
.build();
}
}
6 changes: 6 additions & 0 deletions src/main/java/com/sopterm/makeawish/common/ErrorHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,10 @@ public ResponseEntity<ApiResponse> popbillException(PopbillException exception){
val response = ApiResponse.fail(exception.getMessage());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(AbuseException.class)
public ResponseEntity<ApiResponse> abuseException(AbuseException exception){
val response = ApiResponse.fail(exception.getMessage());
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public enum ErrorMessage {
NULL_PRINCIPAL("principal 이 null 일 수 없습니다."),
NO_EXIST_USER_ACCOUNT("유저의 계좌정보가 없습니다."),
NOT_VALID_USER_ACCOUNT("유저의 계좌번호가 아닙니다."),
IS_ABUSE_USER("어뷰징 유저로 이용 불가합니다."),

/** cake **/
INVALID_CAKE("존재하지 않는 케이크입니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public enum SuccessMessage {
SUCCESS_UPDATE_USER_ACCOUNT_INFO("유저 계좌정보 수정 성공"),
SUCCESS_DELETE_USER("회원 탈퇴 성공"),
SUCCESS_VERIFY_USER_ACCOUNT("유저 계좌정보 인증 성공"),
IS_NOT_ABUSE_USER("어뷰징 유저가 아닙니다."),

/** wish **/
SUCCESS_CREATE_WISH("소원 링크 생성 성공"),
Expand Down
27 changes: 22 additions & 5 deletions src/main/java/com/sopterm/makeawish/controller/UserController.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.sopterm.makeawish.controller;

import com.popbill.api.PopbillException;
import com.sopterm.makeawish.common.ApiResponse;
import com.sopterm.makeawish.domain.user.InternalMemberDetails;
import com.sopterm.makeawish.dto.user.UserAccountRequestDTO;
import com.sopterm.makeawish.dto.user.UserAccountVerifyRequestDTO;
import com.sopterm.makeawish.service.AbuseService;
import com.sopterm.makeawish.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand All @@ -15,6 +16,7 @@
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import static com.sopterm.makeawish.common.message.ErrorMessage.NOT_VALID_USER_ACCOUNT;
import static com.sopterm.makeawish.common.message.ErrorMessage.NO_EXIST_USER_ACCOUNT;
import static com.sopterm.makeawish.common.message.SuccessMessage.*;
import static java.util.Objects.nonNull;
Expand All @@ -27,6 +29,8 @@
public class UserController {

private final UserService userService;
private final AbuseService abuseService;
private static final int VERIFY_ACCOUNT_SUCCESS = 0;

@Operation(summary = "유저 계좌 정보 가져오기")
@GetMapping("/account")
Expand Down Expand Up @@ -60,10 +64,23 @@ public ResponseEntity<ApiResponse> deleteUser(
}

@Operation(summary = "계좌 실명 조회")
@GetMapping("/verify-account")
@PostMapping("/verify-account")
public ResponseEntity<ApiResponse> checkAccountInformation(
@RequestParam String name, @RequestParam String BankCode, @RequestParam String AccountNumber) throws Exception {
userService.verifyUserAccount(name, BankCode, AccountNumber);
return ResponseEntity.ok(ApiResponse.success(SUCCESS_VERIFY_USER_ACCOUNT.getMessage()));
@Parameter(hidden = true) @AuthenticationPrincipal InternalMemberDetails memberDetails,
@RequestBody UserAccountVerifyRequestDTO verifyRequestDTO) throws Exception {
val response = userService.verifyUserAccount(memberDetails.getId(), verifyRequestDTO);
return response == VERIFY_ACCOUNT_SUCCESS
? ResponseEntity.ok(ApiResponse.success(SUCCESS_VERIFY_USER_ACCOUNT.getMessage()))
: ResponseEntity.ok(ApiResponse.fail(NOT_VALID_USER_ACCOUNT.getMessage(), response));
}

@Operation(summary = "어뷰징 유저 확인")
@GetMapping("/abuse")
public ResponseEntity<ApiResponse> checkAbuseUser(
@Parameter(hidden = true) @AuthenticationPrincipal InternalMemberDetails memberDetails
) {
abuseService.checkAbuseUser(memberDetails.getId());
val response = abuseService.countAbuseLogByUser(memberDetails.getId());
return ResponseEntity.ok(ApiResponse.success(IS_NOT_ABUSE_USER.getMessage(), response));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.sopterm.makeawish.dto.wish.UserWishUpdateRequestDTO;
import com.sopterm.makeawish.dto.wish.WishIdRequestDTO;
import com.sopterm.makeawish.dto.wish.WishRequestDTO;
import com.sopterm.makeawish.service.AbuseService;
import com.sopterm.makeawish.service.UserService;
import com.sopterm.makeawish.service.WishService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand Down Expand Up @@ -35,13 +37,15 @@
public class WishController {

private final WishService wishService;
private final AbuseService abuseService;

@Operation(summary = "소원 링크 생성")
@PostMapping
public ResponseEntity<ApiResponse> createWish(
@Parameter(hidden = true) @AuthenticationPrincipal InternalMemberDetails memberDetails,
@RequestBody WishRequestDTO requestDTO
) {
abuseService.checkAbuseUser(memberDetails.getId());
val wishId = wishService.createWish(memberDetails.getId(), requestDTO);
return ResponseEntity
.created(getURI(wishId))
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/com/sopterm/makeawish/domain/abuse/AbuseLog.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.sopterm.makeawish.domain.abuse;

import com.sopterm.makeawish.domain.user.User;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

import static jakarta.persistence.FetchType.LAZY;
import static jakarta.persistence.GenerationType.IDENTITY;

@Entity
@Getter
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class AbuseLog {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "abuse_log_id")
private Long id;

@ManyToOne(fetch = LAZY)
@JoinColumn(name = "user_id")
private User user;

@CreatedDate
protected LocalDateTime createdAt;

@Builder
public AbuseLog(User user){
this.user = user;
}
}
37 changes: 37 additions & 0 deletions src/main/java/com/sopterm/makeawish/domain/abuse/AbuseUser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.sopterm.makeawish.domain.abuse;

import com.sopterm.makeawish.domain.user.User;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

import static jakarta.persistence.FetchType.LAZY;
import static jakarta.persistence.GenerationType.IDENTITY;

@Entity
@Getter
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class AbuseUser {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "abuse_user_id")
private Long id;

@ManyToOne(fetch = LAZY)
@JoinColumn(name = "user_id")
private User user;

@CreatedDate
protected LocalDateTime createdAt;

@Builder
public AbuseUser(User user){
this.user = user;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.sopterm.makeawish.dto.user;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Builder;

@Builder
public record UserAccountVerifyRequestDTO(
String name,
@JsonProperty("bankCode")
String BankCode,
@JsonProperty("accountNumber")
String AccountNumber
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.sopterm.makeawish.repository.abuse;

import com.sopterm.makeawish.domain.abuse.AbuseLog;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface AbuseLogRepository extends JpaRepository<AbuseLog, Long> {
@Query(value = "SELECT COUNT(AL) FROM ABUSE_LOG AL WHERE AL.user_id = :userId and AL.created_at >= (now() - interval '7 days')", nativeQuery = true)
Integer countAbuseLogByUserIdDuringWeekend(@Param("userId") Long userId);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.sopterm.makeawish.repository.abuse;

import com.sopterm.makeawish.domain.abuse.AbuseUser;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface AbuseUserRepository extends JpaRepository<AbuseUser, Long> {
Optional<AbuseUser> findAbuseUserByUserId(Long userId);
}
57 changes: 57 additions & 0 deletions src/main/java/com/sopterm/makeawish/service/AbuseService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package com.sopterm.makeawish.service;

import com.sopterm.makeawish.common.AbuseException;
import com.sopterm.makeawish.domain.abuse.AbuseLog;
import com.sopterm.makeawish.domain.abuse.AbuseUser;
import com.sopterm.makeawish.domain.user.User;
import com.sopterm.makeawish.repository.UserRepository;
import com.sopterm.makeawish.repository.abuse.AbuseLogRepository;
import com.sopterm.makeawish.repository.abuse.AbuseUserRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import static com.sopterm.makeawish.common.message.ErrorMessage.INVALID_USER;
import static com.sopterm.makeawish.common.message.ErrorMessage.IS_ABUSE_USER;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AbuseService {
private final AbuseLogRepository abuseLogRepository;
private final AbuseUserRepository abuseUserRepository;
private final UserRepository userRepository;
private static final int ABUSE_CAUTION_COUNT = 4;

@Transactional
public void createAbuseUser(Long userId) {
abuseUserRepository.save(new AbuseUser(getUser(userId)));
}

public void checkAbuseUser(Long userId) {
abuseUserRepository.findAbuseUserByUserId(userId)
.ifPresent(abuseUser -> {
throw new AbuseException(IS_ABUSE_USER.getMessage());
});
}

@Transactional
public Integer countAbuseLogByUser(Long userId) {
val abuseLogCount = abuseLogRepository.countAbuseLogByUserIdDuringWeekend(userId);
if (abuseLogCount >= ABUSE_CAUTION_COUNT) {
createAbuseUser(userId);
}
return abuseLogCount;
}

public void createAbuseLog(AbuseLog abuseLog){
abuseLogRepository.save(abuseLog);
}

private User getUser(Long userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException(INVALID_USER.getMessage()));
}
}
Loading