Skip to content

Commit

Permalink
develop branch synchronization (#165)
Browse files Browse the repository at this point in the history
  • Loading branch information
jinlee1703 authored Nov 8, 2023
2 parents 1b8bba4 + bf42d02 commit 853e929
Show file tree
Hide file tree
Showing 13 changed files with 132 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,8 @@

import org.swmaestro.repl.gifthub.util.StatusEnum;

public class GptResponseException extends RuntimeException {
private StatusEnum status;

public GptResponseException(String message, StatusEnum status) {
super(message);
this.status = status;
public class GptResponseException extends BusinessException {
public GptResponseException() {
super("GPT 응답이 올바르지 않습니다.", StatusEnum.NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.swmaestro.repl.gifthub.exception;

import org.swmaestro.repl.gifthub.util.StatusEnum;

public class GptTimeoutException extends BusinessException {
public GptTimeoutException() {
super("GPT 요청이 시간초과되었습니다.", StatusEnum.NOT_FOUND);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class GiftcardController {

@GetMapping("/{id}")
@Operation(summary = "공유 정보 요청 메서드", description = "클라이언트에서 요청한 공유 정보를 전달하기 위한 메서드입니다.")
@CrossOrigin(origins = "http://seheon.kr, https://dev.gifthub.kr, https://gifthub.kr")
@CrossOrigin(origins = "http://seheon.kr,https://dev.gifthub.kr,https://gifthub.kr")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "공유하기 정보 조회 성공"),
@ApiResponse(responseCode = "400", description = "만료된 공유하기 정보 접근"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package org.swmaestro.repl.gifthub.giftcard.repository;

import java.util.Optional;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.swmaestro.repl.gifthub.giftcard.entity.Giftcard;

public interface GiftcardRepository extends JpaRepository<Giftcard, String> {
boolean existsByVoucherId(Long id);

Optional<Giftcard> findAllByVoucherId(Long id);
List<Giftcard> findAllByVoucherId(Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Random;
import java.util.UUID;

Expand Down Expand Up @@ -76,7 +77,9 @@ public Giftcard read(String id) {

public Giftcard read(Long voucherId) {
return giftCardRepository.findAllByVoucherId(voucherId)
.stream()
.filter(giftcard -> giftcard.getExpiresAt().isAfter(LocalDateTime.now()))
.findFirst()
.orElseThrow(() -> new BusinessException("존재하지 않는 기프트 카드입니다.", StatusEnum.NOT_FOUND));
}

Expand Down Expand Up @@ -153,7 +156,14 @@ public boolean isExist(String id) {
* @return: 기프트 카드가 존재하는지 여부
*/
public boolean isExist(Long voucherId) {
return giftCardRepository.existsByVoucherId(voucherId);
if (giftCardRepository.existsByVoucherId(voucherId)) {
List<Giftcard> giftCards = giftCardRepository.findAllByVoucherId(voucherId);

return giftCards.stream()
.anyMatch(giftcard -> giftcard.getExpiresAt().isAfter(LocalDateTime.now()));

}
return false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.swmaestro.repl.gifthub.auth.service.UserService;
import org.swmaestro.repl.gifthub.util.JwtProvider;
import org.swmaestro.repl.gifthub.util.Message;
import org.swmaestro.repl.gifthub.util.SuccessMessage;
import org.swmaestro.repl.gifthub.vouchers.dto.OCRDto;
import org.swmaestro.repl.gifthub.vouchers.dto.PresignedUrlResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherAutoSaveRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherListResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherReadResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherSaveRequestDto;
Expand All @@ -28,6 +29,7 @@
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUpdateRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUseRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherUseResponseDto;
import org.swmaestro.repl.gifthub.vouchers.service.PendingVoucherService;
import org.swmaestro.repl.gifthub.vouchers.service.StorageService;
import org.swmaestro.repl.gifthub.vouchers.service.VoucherSaveService;
import org.swmaestro.repl.gifthub.vouchers.service.VoucherService;
Expand All @@ -50,15 +52,17 @@ public class VoucherController {
private final StorageService storageService;
private final JwtProvider jwtProvider;
private final VoucherSaveService voucherSaveService;
private final PendingVoucherService pendingVoucherService;
private final UserService userService;

@GetMapping("/images")
@GetMapping("/images/{extension}")
@Operation(summary = "Voucher 이미지 등록 메서드", description = "클라이언트에서 요청한 기프티콘 이미지를 Amazon S3에 저장하기 위한 메서드입니다. 요청 시 S3 PreSigned URL이 반환됩니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "성공적으로 S3 Presigned URL 반환"),
})
public ResponseEntity<Message> saveVoucherImage(HttpServletRequest request) throws IOException {
public ResponseEntity<Message> saveVoucherImage(HttpServletRequest request, @PathVariable String extension) throws IOException {
PresignedUrlResponseDto presignedUrlResponseDto = PresignedUrlResponseDto.builder()
.presignedUrl(storageService.getPresignedUrlForSaveVoucher("voucher", "PNG"))
.presignedUrl(storageService.getPresignedUrlForSaveVoucher("voucher", extension))
.build();
return ResponseEntity.ok(
SuccessMessage.builder()
Expand Down Expand Up @@ -180,9 +184,11 @@ public ResponseEntity<Message> deleteVoucher(HttpServletRequest request, @PathVa
@ApiResponses({
@ApiResponse(responseCode = "200(202)", description = "기프티콘 등록 요청"),
})
public ResponseEntity<Message> test(HttpServletRequest request, @RequestBody OCRDto ocrDto) throws IOException {
public ResponseEntity<Message> saveVoucher(HttpServletRequest request, @RequestBody VoucherAutoSaveRequestDto voucherAutoSaveRequestDto) throws
IOException {
String username = jwtProvider.getUsername(jwtProvider.resolveToken(request).substring(7));
voucherSaveService.execute(ocrDto, username);
Long pendingId = pendingVoucherService.create(userService.read(username));
voucherSaveService.execute(voucherAutoSaveRequestDto, username, pendingId);
return ResponseEntity.ok(
SuccessMessage.builder()
.path(request.getRequestURI())
Expand Down Expand Up @@ -222,4 +228,21 @@ public ResponseEntity<Message> cancelShareVoucher(HttpServletRequest request, @P
.path(request.getRequestURI())
.build());
}

@GetMapping("/{voucherId}/image")
@Operation(summary = "Voucher 이미지 조회 메서드", description = "클라이언트에서 요청한 기프티콘 이미지를 Amazon S3에서 조회하기 위한 메서드입니다. 요청 시 S3 PreSigned URL이 반환됩니다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "성공적으로 S3 Presigned URL 반환"),
})
public ResponseEntity<Message> readVoucherImage(HttpServletRequest request, @PathVariable Long voucherId) throws IOException {
String username = jwtProvider.getUsername(jwtProvider.resolveToken(request).substring(7));
PresignedUrlResponseDto presignedUrlResponseDto = PresignedUrlResponseDto.builder()
.presignedUrl(voucherService.getPresignedUrlForVoucherImage(username, voucherId))
.build();
return ResponseEntity.ok(
SuccessMessage.builder()
.path(request.getRequestURI())
.data(presignedUrlResponseDto)
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
@Getter
@NoArgsConstructor
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class OCRDto {
public class VoucherAutoSaveRequestDto {
private List<String> texts;
private String filename;

@Builder
public OCRDto(List<String> texts) {
public VoucherAutoSaveRequestDto(List<String> texts, String filename) {
this.texts = texts;
this.filename = filename;
}

public String concatenateTexts() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.swmaestro.repl.gifthub.vouchers.dto.GptResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.OCRDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherAutoSaveRequestDto;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
Expand All @@ -25,9 +25,6 @@ public class GptService {
private String apiUrl;
@Value("${openai.api-key}")
private String apiKey;

// @Value("${openai.question-path}")
// private String promptPath;
private String prompt;

@Autowired
Expand All @@ -38,9 +35,9 @@ public GptService(WebClient.Builder webClientBuilder, @Value("/gpt/question.txt"
this.prompt = loadQuestionFromFile(promptPath);
}

public Mono<GptResponseDto> getGptResponse(OCRDto ocrDto) throws IOException {
public Mono<GptResponseDto> getGptResponse(VoucherAutoSaveRequestDto voucherAutoSaveRequestDto) {
String question = prompt;
String content = ocrDto.concatenateTexts();
String content = voucherAutoSaveRequestDto.concatenateTexts();

String prompt = content + question;
ObjectNode requestBody = objectMapper.createObjectNode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ public String getPresignedUrlForSaveVoucher(String dirName, String extension) {
GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.PUT)
.withExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 5));
return amazonS3Client.generatePresignedUrl(generatePresignedUrlRequest).toString();
return amazonS3Client.generatePresignedUrl(generatePresignedUrlRequest).toString().replace("https://", "http://");
}

public String getPresignedUrl(String dirName, String filename) {
String key = dirName + "/" + filename;
GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest(bucketName, key, HttpMethod.GET)
.withExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 5));
return amazonS3Client.generatePresignedUrl(generatePresignedUrlRequest).toString().replace("https://", "http://");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,23 @@

import org.springframework.stereotype.Service;
import org.swmaestro.repl.gifthub.auth.service.UserService;
import org.swmaestro.repl.gifthub.exception.BusinessException;
import org.swmaestro.repl.gifthub.exception.GptResponseException;
import org.swmaestro.repl.gifthub.exception.TimeoutException;
import org.swmaestro.repl.gifthub.exception.GptTimeoutException;
import org.swmaestro.repl.gifthub.notifications.NotificationType;
import org.swmaestro.repl.gifthub.notifications.service.FCMNotificationService;
import org.swmaestro.repl.gifthub.notifications.service.NotificationService;
import org.swmaestro.repl.gifthub.util.ProductNameProcessor;
import org.swmaestro.repl.gifthub.util.QueryTemplateReader;
import org.swmaestro.repl.gifthub.util.StatusEnum;
import org.swmaestro.repl.gifthub.vouchers.dto.GptResponseDto;
import org.swmaestro.repl.gifthub.vouchers.dto.OCRDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherAutoSaveRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherSaveRequestDto;
import org.swmaestro.repl.gifthub.vouchers.dto.VoucherSaveResponseDto;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.sentry.Sentry;
import lombok.RequiredArgsConstructor;
import reactor.core.publisher.Mono;

Expand All @@ -39,10 +40,9 @@ public class VoucherSaveService {
private final UserService userService;
private final PendingVoucherService pendingVoucherService;

public void execute(OCRDto ocrDto, String username) throws IOException {
Long pendingId = pendingVoucherService.create(userService.read(username));
handleGptResponse(ocrDto, username)
.flatMap(voucherSaveRequestDto -> handleSearchResponse(voucherSaveRequestDto, username))
public void execute(VoucherAutoSaveRequestDto voucherAutoSaveRequestDto, String username, Long pendingId) throws IOException {
String filename = voucherAutoSaveRequestDto.getFilename();
handleGptResponse(voucherAutoSaveRequestDto, username).flatMap(voucherSaveRequestDto -> handleSearchResponse(voucherSaveRequestDto, username, filename))
.flatMap(voucherSaveRequestDto -> handleVoucherSaving(voucherSaveRequestDto, username))
.subscribe(
// onSuccess
Expand All @@ -54,74 +54,64 @@ public void execute(OCRDto ocrDto, String username) throws IOException {
if (voucherService.read(voucherSaveResponseDto.getId()).getExpiresAt().isBefore(LocalDate.now())) {
fcmNotificationService.sendNotification("기프티콘 등록 성공", "만료된 기프티콘을 등록했습니다.", username);
notificationService.save(userService.read(username), voucherService.read(voucherSaveResponseDto.getId()),
NotificationType.REGISTERED,
"만료된 기프티콘을 등록했습니다.");
NotificationType.REGISTERED, "만료된 기프티콘을 등록했습니다.");
} else {
fcmNotificationService.sendNotification("기프티콘 등록 성공", "기프티콘 등록에 성공했습니다!", username);
notificationService.save(userService.read(username), voucherService.read(voucherSaveResponseDto.getId()),
NotificationType.REGISTERED,
"기프티콘 등록에 성공했습니다.");
NotificationType.REGISTERED, "기프티콘 등록에 성공했습니다.");
}
},
// onError
throwable -> {
System.out.println("등록 실패");
Sentry.captureException(throwable);
// 처리 완료
pendingVoucherService.delete(pendingId);
throwable.printStackTrace();
// 15초 이상 응답이 없을 경우
if (throwable instanceof TimeoutException) {
fcmNotificationService.sendNotification("기프티콘 등록 실패", "자동 등록에 실패했습니다. 다시 시도해 주세요", username);
notificationService.save(userService.read(username), null,
NotificationType.REGISTERED,
"GPT 요청이 시간초과되었습니다.");
}
//Gpt 에러일 경우
if (throwable instanceof GptResponseException) {
fcmNotificationService.sendNotification("기프티콘 등록 실패", "자동 등록에 실패했습니다. 수동 등록을 이용해 주세요.", username);
notificationService.save(userService.read(username), null,
NotificationType.REGISTERED,
"자동 등록에 실패했습니다. 수동 등록을 이용해 주세요.");
} else {
if (throwable instanceof BusinessException) {
fcmNotificationService.sendNotification("기프티콘 등록 실패", "이미 등록된 기프티콘 입니다.", username);
notificationService.save(userService.read(username), null,
NotificationType.REGISTERED,
"이미 등록된 기프티콘 입니다.");
notificationService.save(userService.read(username), null, NotificationType.REGISTERED, "이미 등록된 기프티콘 입니다.");
} else {
fcmNotificationService.sendNotification("기프티콘 등록 실패", "자동 등록에 실패했습니다. 수동 등록을 이용해 주세요.", username);
notificationService.save(userService.read(username), null, NotificationType.REGISTERED, "자동 등록에 실패했습니다. 수동 등록을 이용해 주세요.");
}
});
}

public Mono<VoucherSaveRequestDto> handleGptResponse(OCRDto ocrDto, String username) throws IOException, GptResponseException, TimeoutException {
return gptService.getGptResponse(ocrDto)
.timeout(Duration.ofSeconds(15))
.onErrorResume(TimeoutException.class, throwable -> Mono.error(new TimeoutException("GPT 요청이 시간초과되었습니다.", StatusEnum.NOT_FOUND)))
public Mono<VoucherSaveRequestDto> handleGptResponse(VoucherAutoSaveRequestDto voucherAutoSaveRequestDto, String username) throws
GptResponseException,
GptTimeoutException {

return gptService.getGptResponse(voucherAutoSaveRequestDto)
.timeout(Duration.ofMinutes(15))
.onErrorResume(GptTimeoutException.class, throwable -> Mono.error(new GptTimeoutException()))
.flatMap(response -> {
VoucherSaveRequestDto voucherSaveRequestDto = null;
try {
VoucherSaveRequestDto voucherSaveRequestDto = createVoucherSaveRequestDto(response);
if (voucherSaveRequestDto.getBrandName() == "" ||
voucherSaveRequestDto.getProductName() == "" ||
voucherSaveRequestDto.getBarcode() == "" ||
voucherSaveRequestDto.getExpiresAt() == "") {
throw new GptResponseException("GPT 응답이 올바르지 않습니다.", StatusEnum.NOT_FOUND);
}
return Mono.just(voucherSaveRequestDto);
voucherSaveRequestDto = createVoucherSaveRequestDto(response);
} catch (JsonProcessingException e) {
e.printStackTrace();
return Mono.error(new GptResponseException("GPT 응답이 올바르지 않습니다.", StatusEnum.NOT_FOUND));
return Mono.error(new RuntimeException(e));
}
if (voucherSaveRequestDto.getBrandName() == "" || voucherSaveRequestDto.getProductName() == "" || voucherSaveRequestDto.getBarcode() == ""
|| voucherSaveRequestDto.getExpiresAt() == "") {
return Mono.error(new GptResponseException());
}
return Mono.just(voucherSaveRequestDto);
});
}

public Mono<VoucherSaveRequestDto> handleSearchResponse(VoucherSaveRequestDto voucherSaveRequestDto, String username) {
public Mono<VoucherSaveRequestDto> handleSearchResponse(VoucherSaveRequestDto voucherSaveRequestDto, String username, String filename) {
return searchService.search(createQuery(productNameProcessor.preprocessing(voucherSaveRequestDto))).flatMap(searchResponseDto -> {
try {
String brandName = searchResponseDto.getHits().getHitsList().get(0).getSource().getBrandName();
String productName = searchResponseDto.getHits().getHitsList().get(0).getSource().getProductName();
voucherSaveRequestDto.setBrandName(brandName);
voucherSaveRequestDto.setProductName(productName);
voucherSaveRequestDto.setImageUrl(filename);
System.out.println("Search response");
System.out.println(brandName);
System.out.println(productName);
System.out.println(filename);
return Mono.just(voucherSaveRequestDto);
} catch (Exception e) {
e.printStackTrace();
Expand All @@ -148,9 +138,7 @@ private VoucherSaveRequestDto createVoucherSaveRequestDto(GptResponseDto gptResp

private String createQuery(VoucherSaveRequestDto voucherSaveRequestDto) {
String queryTemplate = queryTemplateReader.readQueryTemplate();
return String.format(queryTemplate,
voucherSaveRequestDto.getBrandName(),
voucherSaveRequestDto.getProductName());
return String.format(queryTemplate, voucherSaveRequestDto.getBrandName(), voucherSaveRequestDto.getProductName());
}

}
Loading

0 comments on commit 853e929

Please sign in to comment.