From 22a2b70372cbae45cc2cb64296131512a7461789 Mon Sep 17 00:00:00 2001 From: wlgns12370 Date: Mon, 11 Aug 2025 04:17:33 +0900 Subject: [PATCH 1/5] MOSU refactor: set secure flag to false for development cookies --- .../life/mosu/mosuserver/global/util/CookieBuilderUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/life/mosu/mosuserver/global/util/CookieBuilderUtil.java b/src/main/java/life/mosu/mosuserver/global/util/CookieBuilderUtil.java index 7f5ea9aa..b34fc5e9 100644 --- a/src/main/java/life/mosu/mosuserver/global/util/CookieBuilderUtil.java +++ b/src/main/java/life/mosu/mosuserver/global/util/CookieBuilderUtil.java @@ -65,7 +65,7 @@ public static String createLocalCookieString(String name, String value, Long max public static ResponseCookie createDevelopResponseCookie(String name, String value, Long maxAge) { return createBaseResponseCookieBuilder(name, value, maxAge) - .secure(true) + .secure(false) .domain(".mosuedu.com") .sameSite("Strict") .build(); @@ -81,7 +81,7 @@ public static ResponseCookie createDevelopResponseCookie(String name, String val */ public static Cookie createDevelopCookie(String name, String value, Long maxAge) { Cookie cookie = createBaseServletCookie(name, value, maxAge); - cookie.setSecure(true); + cookie.setSecure(false); cookie.setDomain(".mosuedu.com"); return cookie; } From a01febfb0d7effb56e7d3cbe7d0d65ef6359c332 Mon Sep 17 00:00:00 2001 From: jbh010204 Date: Mon, 11 Aug 2025 04:35:37 +0900 Subject: [PATCH 2/5] feat: enhance inquiry search functionality with answer details and new response DTO --- .../repository/InquiryQueryRepository.java | 3 +- .../jpa/InquiryJpaRepositoryImpl.java | 73 +++++++++++++++---- .../inquiry/dto/InquiryListResponse.java | 14 ++++ 3 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryListResponse.java diff --git a/src/main/java/life/mosu/mosuserver/domain/inquiry/repository/InquiryQueryRepository.java b/src/main/java/life/mosu/mosuserver/domain/inquiry/repository/InquiryQueryRepository.java index f26d0943..84323823 100644 --- a/src/main/java/life/mosu/mosuserver/domain/inquiry/repository/InquiryQueryRepository.java +++ b/src/main/java/life/mosu/mosuserver/domain/inquiry/repository/InquiryQueryRepository.java @@ -1,6 +1,7 @@ package life.mosu.mosuserver.domain.inquiry.repository; import life.mosu.mosuserver.domain.inquiry.entity.InquiryStatus; +import life.mosu.mosuserver.presentation.inquiry.dto.InquiryListResponse; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryResponse; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -10,5 +11,5 @@ public interface InquiryQueryRepository { Page searchInquiries(InquiryStatus status, String sortField, boolean asc, Pageable pageable); - Page searchMyInquiry(Long userId, Pageable pageable); + Page searchMyInquiry(Long userId, Pageable pageable); } diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/InquiryJpaRepositoryImpl.java b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/InquiryJpaRepositoryImpl.java index 2ac21f89..b5ccb9d8 100644 --- a/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/InquiryJpaRepositoryImpl.java +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/InquiryJpaRepositoryImpl.java @@ -15,6 +15,9 @@ import life.mosu.mosuserver.domain.inquiry.entity.InquiryStatus; import life.mosu.mosuserver.domain.inquiry.entity.QInquiryJpaEntity; import life.mosu.mosuserver.domain.inquiry.repository.InquiryQueryRepository; +import life.mosu.mosuserver.domain.inquiryAnswer.entity.QInquiryAnswerJpaEntity; +import life.mosu.mosuserver.presentation.inquiry.dto.InquiryAnswerResponse; +import life.mosu.mosuserver.presentation.inquiry.dto.InquiryListResponse; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryResponse; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; @@ -29,6 +32,7 @@ public class InquiryJpaRepositoryImpl implements InquiryQueryRepository { private final JPAQueryFactory queryFactory; private final EntityManager entityManager; private final QInquiryJpaEntity inquiry = QInquiryJpaEntity.inquiryJpaEntity; + private final QInquiryAnswerJpaEntity inquiryAnswer = QInquiryAnswerJpaEntity.inquiryAnswerJpaEntity; @Override public Page searchInquiries( @@ -38,40 +42,42 @@ public Page searchInquiries( Pageable pageable ) { - JPAQuery query = baseQuery(inquiry) - .where(buildStatusCondition(inquiry, status)) - .orderBy(buildOrderByCondition(sortField, asc)) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize()); + JPAQuery query = baseQuery() + .where(buildStatusCondition(inquiry, status)); long total = getTotalCount(query, inquiry.count()); - List content = query.fetch().stream() - .map(this::mapToResponse) + List content = query + .orderBy(buildOrderByCondition(sortField, asc)) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch().stream() + .map(this::mapToInquiryResponse) .toList(); return new PageImpl<>(content, pageable, total); } @Override - public Page searchMyInquiry(Long userId, Pageable pageable) { - JPAQuery query = baseQuery(inquiry) + public Page searchMyInquiry(Long userId, Pageable pageable) { + JPAQuery query = baseQueryWithAnswer() .where(inquiry.userId.eq(userId)); - long total = getTotalCount(query, inquiry.count()); + long total = getTotalCount(query, inquiry.countDistinct()); - List content = query + List content = query + .orderBy(inquiry.createdAt.desc()) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) .fetch().stream() - .map(this::mapToResponse) + .map(this::mapToInquiryListResponse) .toList(); return new PageImpl<>(content, pageable, total); } - private JPAQuery baseQuery(QInquiryJpaEntity inquiry) { + private JPAQuery baseQuery() { return queryFactory .select( inquiry.id, @@ -85,6 +91,27 @@ private JPAQuery baseQuery(QInquiryJpaEntity inquiry) { } + private JPAQuery baseQueryWithAnswer() { + return queryFactory + .select( + inquiry.id, + inquiry.title, + inquiry.content, + inquiry.author, + inquiry.status, + inquiry.createdAt, + inquiryAnswer.id, + inquiryAnswer.title, + inquiryAnswer.content, + inquiryAnswer.author, + inquiryAnswer.createdAt, + inquiryAnswer.updatedAt + ) + .from(inquiry) + .leftJoin(inquiryAnswer) + .on(inquiryAnswer.inquiryId.eq(inquiry.id)); + } + private BooleanExpression buildStatusCondition(QInquiryJpaEntity inquiry, InquiryStatus status) { return status != null ? inquiry.status.eq(status) : null; @@ -108,7 +135,7 @@ private long getTotalCount(JPAQuery query, Expression countExpressi ).orElse(0L); } - private InquiryResponse mapToResponse(Tuple tuple) { + private InquiryResponse mapToInquiryResponse(Tuple tuple) { InquiryStatus status = tuple.get(inquiry.status); return new InquiryResponse( tuple.get(inquiry.id), @@ -119,4 +146,22 @@ private InquiryResponse mapToResponse(Tuple tuple) { formatDate(tuple.get(inquiry.createdAt)) ); } + + + private InquiryListResponse mapToInquiryListResponse(Tuple tuple) { + InquiryResponse inquiryDto = mapToInquiryResponse(tuple); + InquiryAnswerResponse answerDto = null; + + if (tuple.get(inquiryAnswer.id) != null) { + answerDto = new InquiryAnswerResponse( + tuple.get(inquiryAnswer.title), + tuple.get(inquiryAnswer.content), + tuple.get(inquiryAnswer.author), + formatDate(tuple.get(inquiryAnswer.createdAt)), + formatDate(tuple.get(inquiryAnswer.updatedAt)) + ); + } + + return new InquiryListResponse(inquiryDto, answerDto); + } } diff --git a/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryListResponse.java b/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryListResponse.java new file mode 100644 index 00000000..ba42c635 --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryListResponse.java @@ -0,0 +1,14 @@ +package life.mosu.mosuserver.presentation.inquiry.dto; + +public record InquiryListResponse( + InquiryResponse inquiry, + InquiryAnswerResponse reply +) { + + public static InquiryListResponse of( + InquiryResponse inquiry, + InquiryAnswerResponse reply + ) { + return new InquiryListResponse(inquiry, reply); + } +} From da43546bae5700a38ede889184bfe516782743e5 Mon Sep 17 00:00:00 2001 From: jbh010204 Date: Mon, 11 Aug 2025 04:36:25 +0900 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=EB=82=B4=20=EB=AC=B8=EC=9D=98=20?= =?UTF-8?q?=EB=82=B4=EC=97=AD=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20=EB=8B=B5?= =?UTF-8?q?=EB=B3=80=EB=8F=84=20=EA=B0=99=EC=9D=B4=20=EB=B0=98=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/inquiry/InquiryService.java | 6 ++++-- .../inquiry/InquiryController.java | 12 ++++++----- .../inquiry/InquiryControllerDocs.java | 4 ++-- .../inquiry/dto/InquiryAnswerResponse.java | 20 +++++++++++++++++++ .../inquiry/dto/InquiryResponse.java | 12 +---------- 5 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryAnswerResponse.java diff --git a/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryService.java b/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryService.java index addec98a..faca75b0 100644 --- a/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryService.java +++ b/src/main/java/life/mosu/mosuserver/application/inquiry/InquiryService.java @@ -10,6 +10,7 @@ import life.mosu.mosuserver.presentation.inquiry.dto.InquiryCreateRequest; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryDetailResponse; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryDetailResponse.InquiryAnswerDetailResponse; +import life.mosu.mosuserver.presentation.inquiry.dto.InquiryListResponse; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryResponse; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryUpdateRequest; import lombok.RequiredArgsConstructor; @@ -56,8 +57,9 @@ public InquiryDetailResponse getInquiryDetail(UserJpaEntity user, Long postId) { } @Transactional(readOnly = true, propagation = Propagation.SUPPORTS) - public Page getMyInquiry(Long userId, Pageable pageable) { - return inquiryJpaRepository.searchMyInquiry(userId, pageable); + public Page getMyInquiry(Long userId, Pageable pageable) { + return inquiryJpaRepository.searchMyInquiry(userId, + pageable); } @Transactional diff --git a/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryController.java b/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryController.java index f9bff42d..8d2cb577 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryController.java +++ b/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryController.java @@ -7,7 +7,7 @@ import life.mosu.mosuserver.global.util.ApiResponseWrapper; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryCreateRequest; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryDetailResponse; -import life.mosu.mosuserver.presentation.inquiry.dto.InquiryResponse; +import life.mosu.mosuserver.presentation.inquiry.dto.InquiryListResponse; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryUpdateRequest; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; @@ -54,12 +54,13 @@ public ResponseEntity> update( @GetMapping("/my") @PreAuthorize("isAuthenticated() and hasRole('USER')") - public ResponseEntity>> getMyInquiries( + public ResponseEntity>> getMyInquiries( @UserId Long userId, @PageableDefault(size = 10) Pageable pageable ) { - Page inquiries = inquiryService.getMyInquiry(userId, pageable); - return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "내 질문 목록 조회 성공", inquiries)); + Page inquiries = inquiryService.getMyInquiry(userId, pageable); + return ResponseEntity.ok( + ApiResponseWrapper.success(HttpStatus.OK, "내 질문 목록 조회 성공", inquiries)); } @GetMapping("/{postId}") @@ -68,7 +69,8 @@ public ResponseEntity> getInquiryDetai @AuthenticationPrincipal PrincipalDetails principalDetails, @PathVariable Long postId) { - InquiryDetailResponse inquiry = inquiryService.getInquiryDetail(principalDetails.user(), postId); + InquiryDetailResponse inquiry = inquiryService.getInquiryDetail(principalDetails.user(), + postId); return ResponseEntity.ok(ApiResponseWrapper.success(HttpStatus.OK, "질문 상세 조회 성공", inquiry)); } diff --git a/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryControllerDocs.java b/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryControllerDocs.java index e592404c..f58ebf49 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryControllerDocs.java +++ b/src/main/java/life/mosu/mosuserver/presentation/inquiry/InquiryControllerDocs.java @@ -13,7 +13,7 @@ import life.mosu.mosuserver.global.util.ApiResponseWrapper; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryCreateRequest; import life.mosu.mosuserver.presentation.inquiry.dto.InquiryDetailResponse; -import life.mosu.mosuserver.presentation.inquiry.dto.InquiryResponse; +import life.mosu.mosuserver.presentation.inquiry.dto.InquiryListResponse; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; @@ -37,7 +37,7 @@ ResponseEntity> create( @ApiResponse(responseCode = "200", description = "내 문의글 목록 조회 성공", content = @Content(schema = @Schema(implementation = Page.class))) }) - ResponseEntity>> getMyInquiries( + ResponseEntity>> getMyInquiries( @Parameter(description = "사용자 ID", required = true) Long userId, @Parameter(description = "페이지 정보") Pageable pageable ); diff --git a/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryAnswerResponse.java b/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryAnswerResponse.java new file mode 100644 index 00000000..b98c620d --- /dev/null +++ b/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryAnswerResponse.java @@ -0,0 +1,20 @@ +package life.mosu.mosuserver.presentation.inquiry.dto; + +public record InquiryAnswerResponse( + String title, + String content, + String author, + String createdAt, + String updatedAt +) { + + public static InquiryAnswerResponse of( + String title, + String content, + String author, + String createdAt, + String updatedAt + ) { + return new InquiryAnswerResponse(title, content, author, createdAt, updatedAt); + } +} diff --git a/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryResponse.java b/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryResponse.java index 33332506..e2a8cf04 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryResponse.java +++ b/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryResponse.java @@ -1,7 +1,6 @@ package life.mosu.mosuserver.presentation.inquiry.dto; import io.swagger.v3.oas.annotations.media.Schema; -import life.mosu.mosuserver.domain.inquiry.entity.InquiryJpaEntity; @Schema(description = "1:1 문의 응답 DTO") public record InquiryResponse( @@ -24,14 +23,5 @@ public record InquiryResponse( String createdAt ) { - public static InquiryResponse of(InquiryJpaEntity inquiry) { - return new InquiryResponse( - inquiry.getId(), - inquiry.getTitle(), - inquiry.getContent(), - inquiry.getAuthor(), - inquiry.getStatus().getStatusName(), - inquiry.getCreatedAt() - ); - } + } \ No newline at end of file From 1e4f080a113019332ce4f85c21dbd5b8898479a9 Mon Sep 17 00:00:00 2001 From: jbh010204 Date: Mon, 11 Aug 2025 04:41:27 +0900 Subject: [PATCH 4/5] =?UTF-8?q?refactor:=20=EB=A6=AC=EB=B7=B0=20=EB=82=B4?= =?UTF-8?q?=EC=9A=A9=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../infra/persistence/jpa/InquiryJpaRepositoryImpl.java | 2 +- .../presentation/inquiry/dto/InquiryAnswerResponse.java | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/InquiryJpaRepositoryImpl.java b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/InquiryJpaRepositoryImpl.java index b5ccb9d8..f82c96c5 100644 --- a/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/InquiryJpaRepositoryImpl.java +++ b/src/main/java/life/mosu/mosuserver/infra/persistence/jpa/InquiryJpaRepositoryImpl.java @@ -162,6 +162,6 @@ private InquiryListResponse mapToInquiryListResponse(Tuple tuple) { ); } - return new InquiryListResponse(inquiryDto, answerDto); + return InquiryListResponse.of(inquiryDto, answerDto); } } diff --git a/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryAnswerResponse.java b/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryAnswerResponse.java index b98c620d..a6adb4ad 100644 --- a/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryAnswerResponse.java +++ b/src/main/java/life/mosu/mosuserver/presentation/inquiry/dto/InquiryAnswerResponse.java @@ -8,13 +8,4 @@ public record InquiryAnswerResponse( String updatedAt ) { - public static InquiryAnswerResponse of( - String title, - String content, - String author, - String createdAt, - String updatedAt - ) { - return new InquiryAnswerResponse(title, content, author, createdAt, updatedAt); - } } From f8e123210cce0146ad93ea2fda52a2c896792e6e Mon Sep 17 00:00:00 2001 From: wlgns12370 Date: Mon, 11 Aug 2025 04:42:47 +0900 Subject: [PATCH 5/5] refactor: set secure flag to true for development cookies --- .../life/mosu/mosuserver/global/util/CookieBuilderUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/life/mosu/mosuserver/global/util/CookieBuilderUtil.java b/src/main/java/life/mosu/mosuserver/global/util/CookieBuilderUtil.java index b34fc5e9..7f5ea9aa 100644 --- a/src/main/java/life/mosu/mosuserver/global/util/CookieBuilderUtil.java +++ b/src/main/java/life/mosu/mosuserver/global/util/CookieBuilderUtil.java @@ -65,7 +65,7 @@ public static String createLocalCookieString(String name, String value, Long max public static ResponseCookie createDevelopResponseCookie(String name, String value, Long maxAge) { return createBaseResponseCookieBuilder(name, value, maxAge) - .secure(false) + .secure(true) .domain(".mosuedu.com") .sameSite("Strict") .build(); @@ -81,7 +81,7 @@ public static ResponseCookie createDevelopResponseCookie(String name, String val */ public static Cookie createDevelopCookie(String name, String value, Long maxAge) { Cookie cookie = createBaseServletCookie(name, value, maxAge); - cookie.setSecure(false); + cookie.setSecure(true); cookie.setDomain(".mosuedu.com"); return cookie; }