Skip to content

Commit

Permalink
Implement change-voucher owner to giftcard API (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
jinlee1703 authored Oct 20, 2023
2 parents fcc05df + 71fda92 commit cbf12ef
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
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.RestController;
import org.swmaestro.repl.gifthub.giftcard.dto.GiftcardResponseDto;
import org.swmaestro.repl.gifthub.giftcard.service.GiftcardService;
import org.swmaestro.repl.gifthub.util.BasicAuthenticationDecoder;
import org.swmaestro.repl.gifthub.util.JwtProvider;
import org.swmaestro.repl.gifthub.util.Message;
import org.swmaestro.repl.gifthub.util.SuccessMessage;

Expand All @@ -24,6 +26,7 @@
@Tag(name = "GiftCard", description = "공유하기 관련 API")
public class GiftcardController {
private final GiftcardService giftcardService;
private final JwtProvider jwtProvider;

@GetMapping("/{id}")
@Operation(summary = "공유 정보 요청 메서드", description = "클라이언트에서 요청한 공유 정보를 전달하기 위한 메서드입니다.")
Expand All @@ -41,4 +44,21 @@ public ResponseEntity<Message> read(HttpServletRequest request, @PathVariable St
.data(giftcardResponseDto)
.build());
}

@PostMapping("/{id}/acquire")
@Operation(summary = "기프티콘 소유자 변경 메서드", description = "클라이언트의 요청을 통해 기프티콘 소유자를 변경하기 위한 메서드입니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "공유하기 정보 조회 성공"),
@ApiResponse(responseCode = "404", description = "존재하지 않는 공유하기 정보 접근")
})
public ResponseEntity<Message> changeVoucherUser(
HttpServletRequest request,
@PathVariable String id) {
String username = jwtProvider.getUsername(jwtProvider.resolveToken(request).substring(7));
giftcardService.changeVoucherUser(id, username);
return ResponseEntity.ok(
SuccessMessage.builder()
.path(request.getRequestURI())
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ public Giftcard(String id, Voucher voucher, String message, LocalDateTime expire
this.password = password;
this.expiresAt = expiresAt;
}

public void expire() {
this.expiresAt = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import org.springframework.security.crypto.encrypt.AesBytesEncryptor;
import org.springframework.stereotype.Service;
import org.swmaestro.repl.gifthub.auth.entity.User;
import org.swmaestro.repl.gifthub.auth.service.UserService;
import org.swmaestro.repl.gifthub.exception.BusinessException;
import org.swmaestro.repl.gifthub.giftcard.config.GiftcardConfig;
import org.swmaestro.repl.gifthub.giftcard.dto.GiftcardResponseDto;
Expand All @@ -16,6 +18,7 @@
import org.swmaestro.repl.gifthub.util.StatusEnum;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherShareResponseDto;
import org.swmaestro.repl.gifthub.vouchers.entity.Voucher;
import org.swmaestro.repl.gifthub.vouchers.repository.VoucherRepository;

import lombok.RequiredArgsConstructor;

Expand All @@ -25,7 +28,15 @@ public class GiftcardService {
private final GiftcardRepository giftCardRepository;
private final GiftcardConfig giftcardConfig;
private final AesBytesEncryptor aesBytesEncryptor;

private final UserService userService;
private final VoucherRepository voucherRepository; // 순환 참조로 인해 vocuherService를 사용할 수 없음

/**
* 기프트 카드를 생성합니다.
* @param voucher: 기프트 카드를 생성할 기프티콘
* @param message: 기프트 카드에 담을 메시지
* @return: 생성된 기프트 카드의 id
*/
public VoucherShareResponseDto create(Voucher voucher, String message) {
if (isExist(voucher.getId())) {
throw new BusinessException("이미 공유된 기프티콘입니다.", StatusEnum.BAD_REQUEST);
Expand All @@ -45,14 +56,25 @@ public VoucherShareResponseDto create(Voucher voucher, String message) {
.build();
}

/**
* 기프트 카드를 조회합니다.
* @param id: 조회할 기프트 카드의 id
* @return: 조회된 기프트 카드
*/
public Giftcard read(String id) {
if (!isExist(id)) {
throw new BusinessException("존재하지 않는 링크입니다.", StatusEnum.NOT_FOUND);
throw new BusinessException("존재하지 않는 기프트 카드입니다.", StatusEnum.NOT_FOUND);
}

return giftCardRepository.findById(id).get();
}

/**
* 기프트 카드를 조회합니다.
* @param id: 조회할 기프트 카드의 id
* @param password: 조회할 기프트 카드의 비밀번호
* @return: 조회된 기프트 카드
*/
public GiftcardResponseDto read(String id, String password) {
Giftcard giftcard = read(id);

Expand All @@ -73,29 +95,80 @@ public GiftcardResponseDto read(String id, String password) {
.build();
}

/**
* 기프트 카드의 소유자를 변경합니다.
* @param giftcardId: 변경할 기프트 카드의 id
* @param username: 변경할 소유자의 username
* @return: 변경된 기프트 카드
*/
public Giftcard changeVoucherUser(String giftcardId, String username) {
Giftcard giftcard = read(giftcardId);

if (giftcard.getExpiresAt().isBefore(LocalDateTime.now())) {
throw new BusinessException("만료된 링크입니다.", StatusEnum.BAD_REQUEST);
}

Voucher updatedVoucher = giftcard.getVoucher();
User newUser = userService.read(username);
updatedVoucher.setUser(newUser);
voucherRepository.save(updatedVoucher);

giftcard.expire();
giftCardRepository.save(giftcard);
return giftcard;
}

/**
* 기프트 카드가 존재하는지 확인합니다. (기프트 카드 id로 확인)
* @param id
* @return
*/
public boolean isExist(String id) {
return giftCardRepository.existsById(id);
}

/**
* 기프트 카드가 존재하는지 확인합니다. (기프트 카드의 voucher id로 확인)
* @param voucherId: 기프트 카드의 id
* @return: 기프트 카드가 존재하는지 여부
*/
public boolean isExist(Long voucherId) {
return giftCardRepository.existsByVoucherId(voucherId);
}

/**
* UUID를 생성하는 메서드
* @return: 생성된 UUID
*/
public String generateUUID() {
return UUID.randomUUID().toString();
}

/**
* 4자리의 숫자로 구성된 비밀번호를 생성
* @return: 생성된 비밀번호
*/
public String generatePassword() {
int random = new Random().nextInt(10000);
return String.format("%04d", random);
}

/**
* 비밀번호 복호화 메서드
* @param password: 복호화할 비밀번호
* @return: 복호화된 비밀번호
*/
private String decryptPassword(String password) {
byte[] bytes = ByteArrayUtils.stringToByteArray(password);
byte[] decrypt = aesBytesEncryptor.decrypt(bytes);
return new String(decrypt, StandardCharsets.UTF_8);
}

/**
* 비밀번호 암호화 메서드
* @param password: 암호화할 비밀번호
* @return: 암호화된 비밀번호
*/
private String encryptPassword(String password) {
byte[] bytes = password.getBytes(StandardCharsets.UTF_8);
byte[] encrypt = aesBytesEncryptor.encrypt(bytes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import org.swmaestro.repl.gifthub.giftcard.dto.GiftcardResponseDto;
import org.swmaestro.repl.gifthub.giftcard.entity.Giftcard;
import org.swmaestro.repl.gifthub.giftcard.service.GiftcardService;
import org.swmaestro.repl.gifthub.util.JwtProvider;
import org.swmaestro.repl.gifthub.vouchers.entity.Voucher;

import com.fasterxml.jackson.databind.ObjectMapper;

Expand All @@ -31,6 +34,9 @@ class GiftcardControllerTest {
@MockBean
private GiftcardService giftcardService;

@MockBean
private JwtProvider jwtProvider;

@Test
@WithMockUser(username = "test", roles = "USER")
void read() throws Exception {
Expand Down Expand Up @@ -64,4 +70,35 @@ void read() throws Exception {
.andExpect(jsonPath("$.data.brand_name").value(giftcardResponseDto.getBrandName()))
.andExpect(jsonPath("$.data.expires_at").value(giftcardResponseDto.getExpiresAt().toString()));
}

@Test
@WithMockUser(username = "test", roles = "USER")
void changeVoucherUser() throws Exception {
// given
String giftcardId = "id";
String apiPath = "/giftcards/" + giftcardId + "/acquire";

Voucher voucher = Voucher.builder()
.id(1L)
.build();

Giftcard giftcard = Giftcard.builder()
.id(giftcardId)
.voucher(voucher)
.password("0000")
.message("메시지")
.expiresAt(LocalDate.now().atStartOfDay())
.build();

// when
when(jwtProvider.resolveToken(any())).thenReturn("my_awesome_access_token");
when(jwtProvider.getUsername(anyString())).thenReturn("test");
when(giftcardService.changeVoucherUser(giftcardId, "test")).thenReturn(giftcard);

// then
mockMvc.perform(post(apiPath)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.path").value(apiPath));
}
}

0 comments on commit cbf12ef

Please sign in to comment.