From ad64a4c1bb717b144cc6733aa8013f1880d4fedf Mon Sep 17 00:00:00 2001 From: Jong1 <44349716+donsonioc2010@users.noreply.github.com> Date: Tue, 26 Sep 2023 16:00:33 +0900 Subject: [PATCH] =?UTF-8?q?feat=20:=20=EC=9E=85=EC=B0=B0=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20(#71)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor, feat : 컬럼 추가, 타입변경 및 rename 에 따른 기능 수정 * feat : Scheduling완료, Mail Template 페이지제작 * tempSave * feat : 입찰 기능 구현 * feat : checkout을 위한 Commit * feat : Emial Template 제작중 * feat : 이메일 구현 - 입찰자가 없는 경우 유찰 안내메일 - 관리자가 승인하지 않은 경우 유찰 안내메일 - 경매 시작 안내 메일 - 링크 발송을 위한 Properties 추가 * Issue 수정 * feat : detail페이지 이쁘게 꾸미기 * faet : Front로직 추가~ * Feat : 입찰기능 추가 --- .../PictureBidHistoryRestController.java | 32 ++++++--- .../auction/controller/PictureController.java | 12 +++- ...Dto.java => PictureBiddingRequestDto.java} | 2 +- .../response/PictureAbleBidResponseDto.java | 13 ++++ ...tureBidHistoryAmountCreatedAtResponse.java | 15 ++++ .../service/PictureBidHistoryService.java | 68 ++++++++++++++----- Api/src/main/resources/static/js/bidModal.js | 46 +++++++++---- .../templates/pictures/pictureDetail.html | 43 +++++++----- .../domain/domains/picture/items/Picture.java | 2 +- .../PictureBidHistoryRepository.java | 4 +- .../domain/domains/user/entity/User.java | 3 + Domain/src/main/resources/data.sql | 53 ++++++++++----- 12 files changed, 216 insertions(+), 77 deletions(-) rename Api/src/main/java/picasso/server/api/auction/dto/request/{PictureBiddingValidRequestDto.java => PictureBiddingRequestDto.java} (91%) create mode 100644 Api/src/main/java/picasso/server/api/auction/dto/response/PictureAbleBidResponseDto.java create mode 100644 Api/src/main/java/picasso/server/api/auction/dto/response/PictureBidHistoryAmountCreatedAtResponse.java diff --git a/Api/src/main/java/picasso/server/api/auction/controller/PictureBidHistoryRestController.java b/Api/src/main/java/picasso/server/api/auction/controller/PictureBidHistoryRestController.java index aceb5b85..c6e0971e 100644 --- a/Api/src/main/java/picasso/server/api/auction/controller/PictureBidHistoryRestController.java +++ b/Api/src/main/java/picasso/server/api/auction/controller/PictureBidHistoryRestController.java @@ -5,20 +5,18 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; -import org.springframework.ui.Model; 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.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import picasso.server.api.auction.dto.request.PictureBiddingValidRequestDto; +import picasso.server.api.auction.dto.request.PictureBiddingRequestDto; +import picasso.server.api.auction.dto.response.PictureAbleBidResponseDto; import picasso.server.api.auction.service.PictureBidHistoryService; import picasso.server.common.exception.NotLoginUserRestException; -import picasso.server.domain.domains.picture.items.PictureBidHistory; import picasso.server.domain.domains.user.entity.User; -import java.util.List; - @Slf4j @RequiredArgsConstructor @RestController @@ -34,14 +32,30 @@ public class PictureBidHistoryRestController { */ @PostMapping public ResponseEntity isAblePictureBidding( - @Valid @RequestBody PictureBiddingValidRequestDto requestDto, HttpSession session + @Valid @RequestBody PictureBiddingRequestDto requestDto, HttpSession session + ) { + return ResponseEntity.ok( + pictureBidHistoryService.biddingProcess(session, isSessionHaveLoginUser(session), requestDto) + ); + } + + @GetMapping("/{pictureId}") + public ResponseEntity isAblePictureBidding( + @PathVariable Long pictureId, HttpSession session ) { + return ResponseEntity.ok( + pictureBidHistoryService.getSessionUserBiddingResult( + isSessionHaveLoginUser(session), + pictureId + ) + ); + } + + private User isSessionHaveLoginUser(HttpSession session) { User user = (User) session.getAttribute("loginUser"); if (user == null) { throw NotLoginUserRestException.EXCEPTION; } - return ResponseEntity.ok( - pictureBidHistoryService.biddingProcess(user, requestDto.getPictureId(), requestDto.getAmount()) - ); + return user; } } diff --git a/Api/src/main/java/picasso/server/api/auction/controller/PictureController.java b/Api/src/main/java/picasso/server/api/auction/controller/PictureController.java index fe4d9713..9f37d3b8 100644 --- a/Api/src/main/java/picasso/server/api/auction/controller/PictureController.java +++ b/Api/src/main/java/picasso/server/api/auction/controller/PictureController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; +import picasso.server.api.auction.dto.response.PictureBidHistoryAmountCreatedAtResponse; import picasso.server.api.auction.service.PictureBidHistoryService; import picasso.server.api.auction.service.PictureService; import picasso.server.api.user.service.UserService; @@ -23,6 +24,7 @@ import picasso.server.domain.domains.picture.items.PictureStatus; import picasso.server.domain.domains.user.entity.User; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -137,7 +139,15 @@ public String viewPictureDetail(@PathVariable Long id, Model model) { Picture picture = pictureService.getPictureById(id).orElseThrow(() -> NotFoundException.EXCEPTION); model.addAllAttributes(new HashMap<>() {{ put("picture", picture); - put("pictureBidHistory", pictureBidHistoryService.getBidAmountListDescByPicture(picture)); + put("pictureBidHistory", + pictureBidHistoryService.getBidAmountListDescByPicture(picture) + .stream() + .map( + pictureBidHistory -> PictureBidHistoryAmountCreatedAtResponse.builder() + .bidAmount(String.valueOf(pictureBidHistory.getBidAmount())) + .createdAt(pictureBidHistory.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))) + .build() + ).toList()); put("topBidHistory", pictureBidHistoryService.getTopBidAmountByPicture(picture)); }}); return "pictures/pictureDetail"; diff --git a/Api/src/main/java/picasso/server/api/auction/dto/request/PictureBiddingValidRequestDto.java b/Api/src/main/java/picasso/server/api/auction/dto/request/PictureBiddingRequestDto.java similarity index 91% rename from Api/src/main/java/picasso/server/api/auction/dto/request/PictureBiddingValidRequestDto.java rename to Api/src/main/java/picasso/server/api/auction/dto/request/PictureBiddingRequestDto.java index 6d280850..89eb6c09 100644 --- a/Api/src/main/java/picasso/server/api/auction/dto/request/PictureBiddingValidRequestDto.java +++ b/Api/src/main/java/picasso/server/api/auction/dto/request/PictureBiddingRequestDto.java @@ -8,7 +8,7 @@ * 입찰시, 입찰 가능여부 확인을 위한 RequestDTO */ @Data -public class PictureBiddingValidRequestDto { +public class PictureBiddingRequestDto { @PositiveOrZero @NotNull(message = "PictureId는 필수 입력을 하셔야 합니다.") private Long pictureId; diff --git a/Api/src/main/java/picasso/server/api/auction/dto/response/PictureAbleBidResponseDto.java b/Api/src/main/java/picasso/server/api/auction/dto/response/PictureAbleBidResponseDto.java new file mode 100644 index 00000000..db8f2013 --- /dev/null +++ b/Api/src/main/java/picasso/server/api/auction/dto/response/PictureAbleBidResponseDto.java @@ -0,0 +1,13 @@ +package picasso.server.api.auction.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +@AllArgsConstructor +public class PictureAbleBidResponseDto { + private boolean result; + private String message; +} diff --git a/Api/src/main/java/picasso/server/api/auction/dto/response/PictureBidHistoryAmountCreatedAtResponse.java b/Api/src/main/java/picasso/server/api/auction/dto/response/PictureBidHistoryAmountCreatedAtResponse.java new file mode 100644 index 00000000..2220819b --- /dev/null +++ b/Api/src/main/java/picasso/server/api/auction/dto/response/PictureBidHistoryAmountCreatedAtResponse.java @@ -0,0 +1,15 @@ +package picasso.server.api.auction.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +@AllArgsConstructor +public class PictureBidHistoryAmountCreatedAtResponse { + private String bidAmount; + private String createdAt; +} diff --git a/Api/src/main/java/picasso/server/api/auction/service/PictureBidHistoryService.java b/Api/src/main/java/picasso/server/api/auction/service/PictureBidHistoryService.java index 355c041c..fe33aae0 100644 --- a/Api/src/main/java/picasso/server/api/auction/service/PictureBidHistoryService.java +++ b/Api/src/main/java/picasso/server/api/auction/service/PictureBidHistoryService.java @@ -1,8 +1,12 @@ package picasso.server.api.auction.service; +import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import picasso.server.api.auction.dto.request.PictureBiddingRequestDto; +import picasso.server.api.auction.dto.response.PictureAbleBidResponseDto; import picasso.server.common.exception.NotFoundRestException; import picasso.server.common.exception.NotLoginUserRestException; import picasso.server.domain.domains.picture.items.Picture; @@ -19,6 +23,7 @@ @Slf4j @RequiredArgsConstructor +@Transactional @Service public class PictureBidHistoryService { private final UserRepository userRepository; @@ -40,23 +45,26 @@ public PictureBidHistory getTopBidAmountByPicture(Picture picture) { * @param amount * @return */ - public boolean biddingProcess(User user, Long pictureId, Long amount) { + @Transactional + public boolean biddingProcess(HttpSession session, User user, PictureBiddingRequestDto requestDto) { User findUser = userRepository.findById(user.getId()).orElseThrow(() -> NotLoginUserRestException.EXCEPTION); - Picture findPicture = pictureRepository.findById(pictureId).orElseThrow(() -> NotFoundRestException.EXCEPTION); - Optional optionalTopHistory = pictureBidHistoryRepository.findTopByPictureOrderByBidAmountDesc(findPicture); - //아무도 입찰 신청을 하지 않은 경우 또는 요청한 사용자가 입찰 신청한경우 , DB에 저장 - if (optionalTopHistory.isEmpty() || isAbleBiddingPictureByUser(user, findPicture, optionalTopHistory.get(), amount)) { - PictureBidHistory newBidHistory = PictureBidHistory.builder() - .picture(findPicture) - .user(findUser) - .bidAmount(amount) - .build(); - findPicture.addBidHistory(newBidHistory); - pictureRepository.save(findPicture); - return true; - } - return false; + Picture findPicture = pictureRepository.findById(requestDto.getPictureId()).orElseThrow(() -> NotFoundRestException.EXCEPTION); + List history = pictureBidHistoryRepository.findByPicture(findPicture); + history.add( + PictureBidHistory.builder() + .picture(findPicture) + .user(findUser) + .bidAmount(requestDto.getAmount()) + .build() + ); + + findUser.minusPoint(requestDto.getAmount()); + pictureBidHistoryRepository.findTopByPictureOrderByBidAmountDesc(findPicture).ifPresent(topHistory -> + topHistory.getUser().updatePoint(topHistory.getBidAmount())); + userRepository.save(findUser); + session.setAttribute("loginUser", findUser); + return true; } /** @@ -72,7 +80,35 @@ private boolean isAbleBiddingPictureByUser(User user, Picture picture, PictureBi // 사용자가 최종 입찰자가 아니거나 또는 return !topHistory.getUser().equals(user) && amount <= topHistory.getBidAmount() + picture.getIncrementAmount(); } - + + /** + * 경매 입찰을 진행한 사용자가 입찰이 가능한지를 검증한다. + * @param sessionHaveLoginUser + * @param pictureId + * @return + */ + @Transactional + public PictureAbleBidResponseDto getSessionUserBiddingResult(User sessionHaveLoginUser, Long pictureId) { + Picture findPicture = pictureRepository.findById(pictureId).orElseThrow(() -> NotFoundRestException.EXCEPTION); + Optional optionalTopHistory = pictureBidHistoryRepository.findTopByPictureOrderByBidAmountDesc(findPicture); + if (sessionHaveLoginUser.getEmail().equals(findPicture.getUser().getEmail())) { + return PictureAbleBidResponseDto.builder() + .result(false) + .message("경매품 등록자는 입찰이 불가합니다.") + .build(); + } + + if (optionalTopHistory.isPresent() && optionalTopHistory.get().getUser().getEmail().equals(sessionHaveLoginUser.getEmail())) { + return PictureAbleBidResponseDto.builder() + .result(false) + .message("가장 최근 입찰자 입니다.") + .build(); + } + + return PictureAbleBidResponseDto.builder() + .result(true) + .build(); + } public List retrieveMyBidHistoryList(User user) { return pictureBidHistoryRepository.findAllByUserOrderByCreatedAt(user); } diff --git a/Api/src/main/resources/static/js/bidModal.js b/Api/src/main/resources/static/js/bidModal.js index 60d1b1dd..8e55b699 100644 --- a/Api/src/main/resources/static/js/bidModal.js +++ b/Api/src/main/resources/static/js/bidModal.js @@ -64,7 +64,7 @@ const bidButton = document.getElementById('bidButton') function bidProcess() { let minPictureBidAmount = nowPictureAmountVal+incrementAmountVal if(parseInt(bidInput.value) < minPictureBidAmount){ - alert('입찰 최소 금액은 '+minPictureBidAmount+'원 입니다' ) + alert('입찰 최소 금액은 '+ minPictureBidAmount+'원 입니다' ) return false } @@ -73,27 +73,43 @@ function bidProcess() { return false } + let pictureId = document.getElementById('pictureId') + + //입찰 $.ajax({ - type : 'post', - url : '/user/session-info', + type : 'get', + url : '/api/bidding/'+parseInt(pictureId.value), success : function(data, status, xhr) { - userId = data.userId + console.log(data) + if(data.result) { + $.ajax({ + type: 'post', + url: '/api/bidding', + dataType: 'json', + contentType: 'application/json; charset=utf-8', + data: JSON.stringify({ + "pictureId" : parseInt(pictureId.value), + "amount" : parseInt(bidInput.value) + }), + success : (data, status, xhr) => { + alert('입찰이 완료되었습니다.') + location.reload(); + }, + error: (xhr, status, error) => { + alert('입찰 도중 오류가 발생하였습니다.') + location.reload(); + } + }) + + }else { + alert(data.message) + } }, error : function(xhr, status, error) { - alert('입찰 불가') + alert('입찰 도중 오류가 발생하였습니다.') }, }) - var price = document.getElementById("inputPrice").value; - $.ajax({ - type: 'post', - url: 'urlurlurl', - dataType: 'json', - contentType: 'application/json; charset=utf-8', - data: JSON.stringify({ - "bidPrice" : price - }) - }) } bidButton.addEventListener('click', bidProcess); diff --git a/Api/src/main/resources/templates/pictures/pictureDetail.html b/Api/src/main/resources/templates/pictures/pictureDetail.html index 1f54c062..5988dc5d 100644 --- a/Api/src/main/resources/templates/pictures/pictureDetail.html +++ b/Api/src/main/resources/templates/pictures/pictureDetail.html @@ -11,8 +11,8 @@
- - + +
@@ -100,7 +100,7 @@

- +
@@ -121,16 +121,15 @@
입찰내역 Hist 입찰내역이 존재하지 않습니다. - 입찰내역이 존재합니다. +
    +
  • +
    +
    +
    +
    +
  • +
- -
    -
  • An item
  • -
  • A second item
  • -
  • A third item
  • -
  • A fourth item
  • -
  • And a fifth one
  • -
@@ -155,8 +154,14 @@
입찰내역 Hist

현재 입찰가

- - + +
@@ -164,8 +169,14 @@
입찰내역 Hist

입찰 희망가

- - + +