-
Notifications
You must be signed in to change notification settings - Fork 4
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
경매 신고 등록 및 조회 api 추가 #238
경매 신고 등록 및 조회 api 추가 #238
Changes from 11 commits
71304bf
fd691e4
2f8e0c4
0f701f3
30b8d4a
9f6e38d
7eb3c1d
356a320
f86ee9a
2a8ea44
b99dafe
4c3797a
5b44a01
e3fb3a3
aec9a3a
84c67b1
9e8de4b
2730b0f
0ad9e12
c7b2b86
27940a5
8e99dbb
68d9765
14d08b8
7105a4f
3039ebe
7c4212f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package com.ddang.ddang.report.application; | ||
|
||
import com.ddang.ddang.auction.application.exception.AuctionNotFoundException; | ||
import com.ddang.ddang.auction.domain.Auction; | ||
import com.ddang.ddang.auction.infrastructure.persistence.JpaAuctionRepository; | ||
import com.ddang.ddang.bid.application.dto.LoginUserDto; | ||
import com.ddang.ddang.bid.application.exception.UserNotFoundException; | ||
import com.ddang.ddang.report.application.dto.CreateAuctionReportDto; | ||
import com.ddang.ddang.report.application.dto.ReadAuctionReportDto; | ||
import com.ddang.ddang.report.application.exception.AlreadyReportAuctionException; | ||
import com.ddang.ddang.report.application.exception.InvalidReportAuctionException; | ||
import com.ddang.ddang.report.application.exception.InvalidReporterToAuctionException; | ||
import com.ddang.ddang.report.domain.AuctionReport; | ||
import com.ddang.ddang.report.infrastructure.persistence.JpaAuctionReportRepository; | ||
import com.ddang.ddang.user.domain.User; | ||
import com.ddang.ddang.user.infrastructure.persistence.JpaUserRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
|
||
@Service | ||
@Transactional(readOnly = true) | ||
@RequiredArgsConstructor | ||
public class AuctionReportService { | ||
|
||
private final JpaAuctionRepository auctionRepository; | ||
private final JpaUserRepository userRepository; | ||
private final JpaAuctionReportRepository auctionReportRepository; | ||
|
||
public Long create(final LoginUserDto userDto, final CreateAuctionReportDto auctionReportDto) { | ||
// TODO: 2023/08/08 추후 User 패키지 내에 UserNotFoundException이 생긴다면 해당 예외를 사용하도록 수정 하겠습니다. | ||
final User reporter = userRepository.findById(userDto.usedId()) | ||
.orElseThrow(() -> new UserNotFoundException("해당 사용자를 찾을 수 없습니다.")); | ||
final Auction auction = auctionRepository.findById(auctionReportDto.auctionId()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 지토, 엔초 코드에서는 레포지토리 조회 로직을 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
.orElseThrow(() -> new AuctionNotFoundException("해당 경매를 찾을 수 없습니다.")); | ||
invalidReportAuction(reporter, auction); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. entity 이름이 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 통일성을 위해 |
||
|
||
final AuctionReport auctionReport = auctionReportDto.toEntity(reporter, auction); | ||
return auctionReportRepository.save(auctionReport) | ||
.getId(); | ||
} | ||
|
||
private void invalidReportAuction(final User reporter, final Auction auction) { | ||
if (auction.isOwner(reporter)) { | ||
throw new InvalidReporterToAuctionException("본인 경매글입니다."); | ||
} | ||
if (auction.isDeleted()) { | ||
throw new InvalidReportAuctionException("이미 삭제된 경매입니다."); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 위에서 건의드린 내용과 비슷한 맥락으로 위의 두 분기문을 Auction으로 옮겨서 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 의견에 대해 위 코멘트에 댓글 달아두었습니다! |
||
if (auctionReportRepository.existsByAuctionIdAndReporterId(auction.getId(), reporter.getId())) { | ||
throw new AlreadyReportAuctionException("이미 신고한 경매입니다."); | ||
} | ||
} | ||
|
||
public List<ReadAuctionReportDto> readAll() { | ||
final List<AuctionReport> auctionReports = auctionReportRepository.findAll(); | ||
return auctionReports.stream() | ||
.map(ReadAuctionReportDto::from) | ||
.toList(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package com.ddang.ddang.report.application.dto; | ||
|
||
import com.ddang.ddang.auction.domain.Auction; | ||
import com.ddang.ddang.report.domain.AuctionReport; | ||
import com.ddang.ddang.report.presentation.dto.CreateAuctionReportRequest; | ||
import com.ddang.ddang.user.domain.User; | ||
|
||
public record CreateAuctionReportDto(Long auctionId, String description) { | ||
|
||
public static CreateAuctionReportDto from(final CreateAuctionReportRequest auctionReportRequest) { | ||
return new CreateAuctionReportDto(auctionReportRequest.auctionId(), auctionReportRequest.description()); | ||
} | ||
|
||
public AuctionReport toEntity(final User reporter, final Auction auction) { | ||
return new AuctionReport(reporter, auction, this.description); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package com.ddang.ddang.report.application.dto; | ||
|
||
import com.ddang.ddang.auction.domain.Auction; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
public record ReadAuctionDto( | ||
Long id, | ||
String title, | ||
String description, | ||
int bidUnit, | ||
int startPrice, | ||
boolean deleted, | ||
LocalDateTime closingTime, | ||
int auctioneerCount | ||
) { | ||
|
||
public static ReadAuctionDto from(final Auction auction) { | ||
return new ReadAuctionDto( | ||
auction.getId(), | ||
auction.getTitle(), | ||
auction.getDescription(), | ||
auction.getBidUnit().getValue(), | ||
auction.getStartPrice().getValue(), | ||
auction.isDeleted(), | ||
auction.getClosingTime(), | ||
auction.getAuctioneerCount() | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.ddang.ddang.report.application.dto; | ||
|
||
import com.ddang.ddang.report.domain.AuctionReport; | ||
|
||
import java.time.LocalDateTime; | ||
|
||
public record ReadAuctionReportDto( | ||
Long id, | ||
ReadReporterDto reporterDto, | ||
LocalDateTime createdTime, | ||
ReadAuctionDto auctionDto, | ||
String description | ||
) { | ||
|
||
// TODO: 2023/08/08 [고민] ReadAuctionDto 클래스가 같은 이름으로 여러 패키지에 존재함. 이때, import를 할 때 헷갈리거나 실수하지는 않을까요? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 부분은 충분히 혼동될 수 있을 것 같습니다 |
||
public static ReadAuctionReportDto from(AuctionReport auctionReport) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ㅍ..파이널을 발견해버렸습니다.. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 으아니...! final 실수가 있었을 줄이야... (이마짚) |
||
return new ReadAuctionReportDto( | ||
auctionReport.getId(), | ||
ReadReporterDto.from(auctionReport.getReporter()), | ||
auctionReport.getCreatedTime(), | ||
ReadAuctionDto.from(auctionReport.getAuction()), | ||
auctionReport.getDescription() | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.ddang.ddang.report.application.dto; | ||
|
||
import com.ddang.ddang.user.domain.User; | ||
|
||
public record ReadReporterDto(Long id, String name, String profileImage, double reliability) { | ||
|
||
public static ReadReporterDto from(final User reporter) { | ||
return new ReadReporterDto( | ||
reporter.getId(), | ||
reporter.getName(), | ||
reporter.getProfileImage(), | ||
reporter.getReliability() | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.ddang.ddang.report.application.exception; | ||
|
||
public class AlreadyReportAuctionException extends IllegalArgumentException { | ||
|
||
public AlreadyReportAuctionException(final String message) { | ||
super(message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.ddang.ddang.report.application.exception; | ||
|
||
public class InvalidReportAuctionException extends IllegalArgumentException { | ||
public InvalidReportAuctionException(final String message) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클래스와 생성자 사이 개행 추가 부탁드립니당 |
||
super(message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.ddang.ddang.report.application.exception; | ||
|
||
public class InvalidReporterToAuctionException extends IllegalArgumentException { | ||
public InvalidReporterToAuctionException(final String message) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클래스와 생성자 사이 개행 추가 부탁드립니당 22 |
||
super(message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package com.ddang.ddang.report.domain; | ||
|
||
import com.ddang.ddang.auction.domain.Auction; | ||
import com.ddang.ddang.common.entity.BaseCreateTimeEntity; | ||
import com.ddang.ddang.user.domain.User; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.FetchType; | ||
import jakarta.persistence.ForeignKey; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.JoinColumn; | ||
import jakarta.persistence.ManyToOne; | ||
import lombok.AccessLevel; | ||
import lombok.EqualsAndHashCode; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.ToString; | ||
|
||
@Entity | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@Getter | ||
@EqualsAndHashCode(of = "id") | ||
@ToString(of = {"id"}) | ||
public class AuctionReport extends BaseCreateTimeEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "reporter_id", foreignKey = @ForeignKey(name = "fk_auction_report_reporter")) | ||
private User reporter; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "auction_id", foreignKey = @ForeignKey(name = "fk_auction_report_auction")) | ||
private Auction auction; | ||
|
||
@Column(columnDefinition = "text") | ||
private String description; | ||
|
||
public AuctionReport(final User reporter, final Auction auction, final String description) { | ||
this.reporter = reporter; | ||
this.auction = auction; | ||
this.description = description; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.ddang.ddang.report.infrastructure.persistence; | ||
|
||
import com.ddang.ddang.report.domain.AuctionReport; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface JpaAuctionReportRepository extends JpaRepository<AuctionReport, Long>, QuerydslAuctionReportRepository { | ||
|
||
boolean existsByAuctionIdAndReporterId(final Long auctionId, final Long reporterId); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.ddang.ddang.report.infrastructure.persistence; | ||
|
||
import com.ddang.ddang.report.domain.AuctionReport; | ||
|
||
import java.util.List; | ||
|
||
public interface QuerydslAuctionReportRepository { | ||
|
||
List<AuctionReport> findAll(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.ddang.ddang.report.infrastructure.persistence; | ||
|
||
import com.ddang.ddang.report.domain.AuctionReport; | ||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import java.util.List; | ||
|
||
import static com.ddang.ddang.report.domain.QAuctionReport.auctionReport; | ||
|
||
@Repository | ||
@RequiredArgsConstructor | ||
public class QuerydslAuctionReportRepositoryImpl implements QuerydslAuctionReportRepository { | ||
|
||
private final JPAQueryFactory queryFactory; | ||
|
||
@Override | ||
public List<AuctionReport> findAll() { | ||
return queryFactory.selectFrom(auctionReport) | ||
.leftJoin(auctionReport.reporter).fetchJoin() | ||
.leftJoin(auctionReport.auction).fetchJoin() | ||
.fetch(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 해당 메서드는 그렇게 복잡하지 않아 EntityGraph나 JPQL로도 처리할 수 있을 것 같은데 Querydsl로 하신 의도가 무엇인지 궁금합니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저도 궁금합니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 개인적으로 JPQL은 join이 두 개이상부 터는 보기 싫더라고요... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 보기 싫은건 공감이 되기는 하네요.. |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
해당 로직과 동일한 로직이 chatRoomService에도 존재합니다!
이 메서드를 Auction으로 옮기면 어떤지에 대해 엔초 PR에 코멘트를 남겼었는데,
Auction에 해당 메서드를 옮기고 bidService와 chatRoomService에서 Auction의 메서드를 사용하는 것은 어떤지 건의드려봅니다~!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
도메인으로 넣자는 이야기가 맞을까요?
맞다면 개인적으로 도메인에서 예외를 관리하는 게 좋을지 아직은 잘 판단이 되지 않습니다.
또한, 항상 검증에 대한 로직이 동일할 것이라 생각하지 않습니다.
예를 들어
AuctionReportService
에서는 삭제된 경매에 대해서만 예외를 발생시키고 종료된 경매에 대해서는 정상 처리하게 됩니다. (물론 종료에 대해서도 예외가 필요하단 의견이 있다면 수정되겠지만요!)그러면 어떤 건
auction
에서 어떤 건 각 서비스에서 검증을 하게 되는데 그때의 기준이 모호해지지 않을까 하는 걱정이 있습니다.이에 대한 메리 혹은 다른 분들의 의견이 궁금합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저는 해당 분기문이 경매에 대한 상태를 조회한다고 생각했습니다
그리고 언제 경매의 상태가 변경되는지는 도메인 로직이라고 생각해서 도메인에 들어가면 자연스러울 것 같다고 생각했어요
그런데 말씀해주신 것처럼 서비스와 도메인으로 예외 검증 위치가 분산된다는 점이 가독성을 해칠 수도 있을 것 같다는 의견에 동의합니다!
다른 분들의 의견도 궁금합니당
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
서비스마다 검증 내부 로직이 다를 수 있기 때문에 검증에 대한 처리를 auction에 넣는 것에 대해서는 지금처럼 서비스에서 하는 것이 좋다고 생각합니다.
메리가 저한테 리뷰 남겨주신 것은 경매의 상태를 판단해서 enum으로 반환하는 메서드를 경매 엔티티에 넣자는 의견이었던 것 같은데 그 부분에 대해서 다른 분들(@apptie @JJ503)은 어떻게 생각하시나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kwonyj1022 그거 관련 이슈..가 있기는 했는데 까먹고...방치한지 오래되기는 했네요..
enum으로 반환해주기는 해야하는데...