From 4db95fc0a62d47e7567cf2d3f189ff84a4365170 Mon Sep 17 00:00:00 2001 From: gaguriee <74501631+gaguriee@users.noreply.github.com> Date: Fri, 9 Aug 2024 20:53:41 +0900 Subject: [PATCH 1/7] =?UTF-8?q?FEAT=20:=20=EB=82=B4=20=EC=B1=8C=EB=A6=B0?= =?UTF-8?q?=EC=A7=80=20=EC=9D=B8=EC=A6=9D=EB=82=B4=EC=97=AD=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/MyChallengeProofResponse.java | 23 +++++++++++++++ .../service/ChallengeProofService.java | 29 +++++++++++++++++++ .../fledgeserver/exception/ErrorCode.java | 6 ++-- 3 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/fledge/fledgeserver/challenge/dto/MyChallengeProofResponse.java diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/MyChallengeProofResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/MyChallengeProofResponse.java new file mode 100644 index 0000000..9671ac8 --- /dev/null +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/MyChallengeProofResponse.java @@ -0,0 +1,23 @@ +package com.fledge.fledgeserver.challenge.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "본인 챌린지 인증 내역 응답 DTO") +public class MyChallengeProofResponse { + + @Schema(description = "필요한 인증 총 횟수", example = "7") + private int totalProofs; + + @Schema(description = "현재 인증 내역 리스트") + private List proofDetails; +} diff --git a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeProofService.java b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeProofService.java index c7b99cb..b90c00e 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeProofService.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeProofService.java @@ -1,6 +1,10 @@ package com.fledge.fledgeserver.challenge.service; import com.fledge.fledgeserver.canary.repository.CanaryProfileRepository; +import com.fledge.fledgeserver.challenge.dto.MyChallengeProofResponse; +import com.fledge.fledgeserver.challenge.dto.ProofDetail; +import com.fledge.fledgeserver.challenge.entity.ChallengeParticipation; +import com.fledge.fledgeserver.challenge.repository.ChallengeParticipationRepository; import com.fledge.fledgeserver.challenge.repository.ChallengeProofRepository; import com.fledge.fledgeserver.challenge.dto.ChallengeProofResponse; import com.fledge.fledgeserver.challenge.entity.ChallengeProof; @@ -13,12 +17,15 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; +import java.util.List; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class ChallengeProofService { private final ChallengeProofRepository proofRepository; + private final ChallengeParticipationRepository participationRepository; private final CanaryProfileRepository canaryProfileRepository; @Transactional @@ -40,5 +47,27 @@ public ChallengeProofResponse uploadProof(Long participationId, LocalDate proofD return new ChallengeProofResponse(proof); } + + @Transactional(readOnly = true) + public MyChallengeProofResponse getMyProofsByChallengeId(Long challengeId) { + Member member = SecurityUtils.getCurrentMember(); + if (!canaryProfileRepository.existsByMemberAndApprovalStatusIsTrue(member)){ + throw new CustomException(ErrorCode.CANARY_NOT_FOUND, "인증된 자립준비 청년이 아닙니다."); + } + + ChallengeParticipation participation = participationRepository.findByMemberIdAndChallengeId(member.getId(), challengeId) + .orElseThrow(() -> new CustomException(ErrorCode.CHALLENGE_PARTICIPATION_NOT_FOUND)); + + List proofDetails = proofRepository.findByParticipationId(participation.getId()).stream() + .map(proof -> new ProofDetail( + proof.isProofed(), + proof.getProofImageUrl(), + proof.getProofDescription() + )).collect(Collectors.toList()); + + int totalProofs = proofDetails.size(); + + return new MyChallengeProofResponse(totalProofs, proofDetails); + } } diff --git a/src/main/java/com/fledge/fledgeserver/exception/ErrorCode.java b/src/main/java/com/fledge/fledgeserver/exception/ErrorCode.java index 2280948..f21856b 100644 --- a/src/main/java/com/fledge/fledgeserver/exception/ErrorCode.java +++ b/src/main/java/com/fledge/fledgeserver/exception/ErrorCode.java @@ -43,8 +43,10 @@ public enum ErrorCode { CHALLENGE_NOT_FOUND(NOT_FOUND, "챌린지를 찾을 수 없습니다."), CHALLENGE_TYPE_INVALID(BAD_REQUEST, "챌린지 타입이 올바르지 않습니다."), CHALLENGE_PROOF_NOT_FOUND(NOT_FOUND, "챌린지 인증을 찾을 수 없습니다."), - CHALLENGE_PROOF_ALREADY_SUBMITTED(HttpStatus.BAD_REQUEST, "이미 제출된 인증입니다."), - CHALLENGE_FREQUENCY_INVALID(HttpStatus.BAD_REQUEST, "챌린지 빈도가 올바르지 않습니다."); + CHALLENGE_PROOF_ALREADY_SUBMITTED(BAD_REQUEST, "이미 제출된 인증입니다."), + CHALLENGE_FREQUENCY_INVALID(BAD_REQUEST, "챌린지 빈도가 올바르지 않습니다."), + CHALLENGE_PARTICIPATION_NOT_FOUND(BAD_REQUEST, "챌린지 참여 정보를 찾을 수 없습니다."), + CHALLENGE_PARTICIPATION_ALREADY_EXISTS(BAD_REQUEST, "해당 챌린지에 이미 참여 중입니다."); private final HttpStatus httpStatus; private final String message; From 888fbd296897d18f6e2770f0d17708ae5ce1e45b Mon Sep 17 00:00:00 2001 From: gaguriee <74501631+gaguriee@users.noreply.github.com> Date: Fri, 9 Aug 2024 20:55:06 +0900 Subject: [PATCH 2/7] =?UTF-8?q?FEAT=20:=20=ED=95=A8=EA=BB=98=20=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=ED=95=98=EB=8A=94=20=EC=B1=8C=EB=A6=B0=EC=A0=80=20?= =?UTF-8?q?=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ChallengerParticipationPersonResponse.java | 32 +++++++++++++++++++ .../ChallengeParticipationRepository.java | 12 +++++++ .../ChallengeParticipationService.java | 24 ++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengerParticipationPersonResponse.java diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengerParticipationPersonResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengerParticipationPersonResponse.java new file mode 100644 index 0000000..31460de --- /dev/null +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengerParticipationPersonResponse.java @@ -0,0 +1,32 @@ +package com.fledge.fledgeserver.challenge.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "챌린지 참여자 정보 응답 DTO") +public class ChallengerParticipationPersonResponse { + + @Schema(description = "참여자 닉네임", example = "user123") + private String nickname; + + @Schema(description = "참여자 프로필 이미지 URL", example = "https://example.com/profile.jpg") + private String profileImageUrl; + + @Schema(description = "성공한 챌린지 수", example = "5") + private long successCount; + + @Schema(description = "전체 참여 챌린지 수", example = "10") + private long totalParticipation; + + @Schema(description = "자주 참여하는 챌린지 카테고리 목록", example = "[\"SELF_DEVELOPMENT\", \"FITNESS\"]") + private List topCategories; +} diff --git a/src/main/java/com/fledge/fledgeserver/challenge/repository/ChallengeParticipationRepository.java b/src/main/java/com/fledge/fledgeserver/challenge/repository/ChallengeParticipationRepository.java index 1e6c171..bc47e71 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/repository/ChallengeParticipationRepository.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/repository/ChallengeParticipationRepository.java @@ -7,6 +7,7 @@ import org.springframework.data.repository.query.Param; import java.util.List; +import java.util.Optional; public interface ChallengeParticipationRepository extends JpaRepository { @@ -26,4 +27,15 @@ public interface ChallengeParticipationRepository extends JpaRepository findTopCategoriesByMemberId(@Param("memberId") Long memberId); + + Optional findByMemberIdAndChallengeId(Long memberId, Long challengeId); + + List findByChallengeId(Long challengeId); + + @Query("SELECT COUNT(cp) FROM ChallengeParticipation cp WHERE cp.member.id = :memberId AND cp.isSuccess = true") + long countSuccessByMemberId(@Param("memberId") Long memberId); + + long countByMemberId(Long id); + + boolean existsByMemberIdAndChallengeId(Long memberId, Long challengeId); } diff --git a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeParticipationService.java b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeParticipationService.java index 0b10e74..00600c0 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeParticipationService.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeParticipationService.java @@ -1,6 +1,7 @@ package com.fledge.fledgeserver.challenge.service; import com.fledge.fledgeserver.canary.repository.CanaryProfileRepository; +import com.fledge.fledgeserver.challenge.dto.ChallengerParticipationPersonResponse; import com.fledge.fledgeserver.challenge.repository.ChallengeRepository; import com.fledge.fledgeserver.challenge.Enum.Frequency; import com.fledge.fledgeserver.challenge.dto.TopParticipantResponse; @@ -41,6 +42,10 @@ public ChallengeParticipationResponse participateInChallenge(Long memberId, Long throw new CustomException(ErrorCode.CANARY_NOT_FOUND, "인증된 자립준비 청년이 아닙니다."); } + if (participationRepository.existsByMemberIdAndChallengeId(memberId, challengeId)) { + throw new CustomException(ErrorCode.CHALLENGE_PARTICIPATION_ALREADY_EXISTS); + } + Challenge challenge = challengeRepository.findById(challengeId) .orElseThrow(() -> new CustomException(ErrorCode.CHALLENGE_NOT_FOUND)); @@ -145,5 +150,24 @@ public void checkMissedProofs() { } } } + + @Transactional(readOnly = true) + public List getParticipantsByChallengeId(Long challengeId) { + List participations = participationRepository.findByChallengeId(challengeId); + return participations.stream().map(participation -> { + Member member = participation.getMember(); + long successCount = participationRepository.countSuccessByMemberId(member.getId()); + long totalParticipation = participationRepository.countByMemberId(member.getId()); + List topCategories = participationRepository.findTopCategoriesByMemberId(member.getId()); + + return new ChallengerParticipationPersonResponse( + member.getNickname(), + member.getProfile(), + successCount, + totalParticipation, + topCategories + ); + }).collect(Collectors.toList()); + } } From 628a0b74b8767271aba80b9ef5d761dd20b62143 Mon Sep 17 00:00:00 2001 From: gaguriee <74501631+gaguriee@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:03:14 +0900 Subject: [PATCH 3/7] =?UTF-8?q?FEAT=20:=20=EC=B1=8C=EB=A6=B0=EC=A7=80=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ChallengeController.java | 13 +++---- .../controller/PublicChallengeController.java | 21 +++++++++-- .../dto/ChallengeDetailResponse.java | 23 ++++++++++++ .../challenge/dto/ChallengeResponse.java | 3 ++ .../challenge/dto/ProofDetail.java | 25 +++++++++++++ .../challenge/entity/ChallengeProof.java | 5 ++- .../challenge/service/ChallengeService.java | 35 ++++++++++++++++--- .../common/utils/SecurityUtils.java | 4 +++ .../fledgeserver/response/SuccessStatus.java | 5 ++- 9 files changed, 120 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeDetailResponse.java create mode 100644 src/main/java/com/fledge/fledgeserver/challenge/dto/ProofDetail.java diff --git a/src/main/java/com/fledge/fledgeserver/challenge/controller/ChallengeController.java b/src/main/java/com/fledge/fledgeserver/challenge/controller/ChallengeController.java index 8828074..13f9a0e 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/controller/ChallengeController.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/controller/ChallengeController.java @@ -1,22 +1,16 @@ package com.fledge.fledgeserver.challenge.controller; -import com.fledge.fledgeserver.challenge.Enum.ChallengeCategory; import com.fledge.fledgeserver.challenge.dto.*; import com.fledge.fledgeserver.challenge.service.ChallengeParticipationService; import com.fledge.fledgeserver.challenge.service.ChallengeProofService; -import com.fledge.fledgeserver.challenge.service.ChallengeService; import com.fledge.fledgeserver.response.ApiResponse; import com.fledge.fledgeserver.response.SuccessStatus; import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Page; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.List; - @Tag(name = "챌린지 관련 API", description = "챌린지 등록 및 조회, 참여와 관련된 API") @RestController @RequiredArgsConstructor @@ -42,6 +36,13 @@ public ResponseEntity> uploadProof( return ApiResponse.success(SuccessStatus.CHALLENGE_PROOF_UPLOAD_SUCCESS, response); } + @Operation(summary = "챌린지 인증 내역 조회", description = "특정 챌린지에 대해 사용자의 인증 내역을 조회합니다.") + @GetMapping("/{challengeId}/my-proof") + public ResponseEntity> getMyChallengeProofs(@PathVariable Long challengeId) { + MyChallengeProofResponse response = proofService.getMyProofsByChallengeId(challengeId); + return ApiResponse.success(SuccessStatus.CHALLENGE_PROOFS_RETRIEVED_SUCCESS, response); + } + } diff --git a/src/main/java/com/fledge/fledgeserver/challenge/controller/PublicChallengeController.java b/src/main/java/com/fledge/fledgeserver/challenge/controller/PublicChallengeController.java index 31828c7..e592d45 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/controller/PublicChallengeController.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/controller/PublicChallengeController.java @@ -3,7 +3,6 @@ import com.fledge.fledgeserver.challenge.Enum.ChallengeCategory; import com.fledge.fledgeserver.challenge.dto.*; import com.fledge.fledgeserver.challenge.service.ChallengeParticipationService; -import com.fledge.fledgeserver.challenge.service.ChallengeProofService; import com.fledge.fledgeserver.challenge.service.ChallengeService; import com.fledge.fledgeserver.response.ApiResponse; import com.fledge.fledgeserver.response.SuccessStatus; @@ -26,7 +25,7 @@ public class PublicChallengeController { private final ChallengeService challengeService; private final ChallengeParticipationService participationService; - @Operation(summary = "일반 챌린지 조회", description = "좋아요 수 또는 등록일로 정렬된 챌린지 리스트를 조회합니다. 일반 챌린지만 포함됩니다.") + @Operation(summary = "일반 챌린지 리스트 조회", description = "좋아요 수 또는 등록일로 정렬된 챌린지 리스트를 조회합니다. 일반 챌린지만 포함됩니다.") @GetMapping public ResponseEntity>> getChallenges( @Parameter(example = "0") @@ -42,6 +41,16 @@ public ResponseEntity>> getChallenges( return ApiResponse.success(SuccessStatus.CHALLENGE_RETRIEVAL_SUCCESS, challengeResponses); } + @Operation(summary = "일반 챌린지 상세 조회", description = "일반 챌린지 ID를 통해 특정 챌린지의 상세 정보를 조회합니다.") + @GetMapping("/{challengeId}") + public ResponseEntity> getChallengeById( + @Parameter(description = "챌린지 ID", example = "1") + @PathVariable Long challengeId) { + + ChallengeResponse challengeDetail = challengeService.getChallengeById(challengeId); + return ApiResponse.success(SuccessStatus.CHALLENGE_RETRIEVAL_SUCCESS, challengeDetail); + } + @Operation(summary = "연계챌린지 조회", description = "PARTNERSHIP 및 ORGANIZATION 타입의 챌린지를 조회합니다.") @GetMapping("/partnership-and-organization") public ResponseEntity>> getPartnershipAndOrganizationChallenges( @@ -63,6 +72,14 @@ public ResponseEntity>> getTopParticipa return ApiResponse.success(SuccessStatus.CHALLENGE_RETRIEVAL_SUCCESS, topParticipants); } + @Operation(summary = "챌린지 참여자 목록 조회", description = "특정 챌린지에 참여 중인 사용자들의 목록을 조회합니다.") + @GetMapping("/{challengeId}/participants") + public ResponseEntity>> getChallengeParticipants(@PathVariable Long challengeId) { + List participants = participationService.getParticipantsByChallengeId(challengeId); + return ApiResponse.success(SuccessStatus.CHALLENGE_PARTICIPANTS_RETRIEVED_SUCCESS, participants); + } + + } diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeDetailResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeDetailResponse.java new file mode 100644 index 0000000..f727b33 --- /dev/null +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeDetailResponse.java @@ -0,0 +1,23 @@ +package com.fledge.fledgeserver.challenge.dto; + +import com.fledge.fledgeserver.challenge.Enum.ChallengeCategory; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@Schema(description = "챌린지 상세 정보 응답 DTO") +public class ChallengeDetailResponse extends ChallengeResponse { + + @Schema(description = "사용자 참여 여부", example = "true") + private boolean isParticipating; + + public ChallengeDetailResponse(String title, int likeCount, List categories, String type, + String description, double successRate, int successCount, int participantCount, boolean isParticipating) { + super(title, likeCount, categories, type, description, successRate, successCount, participantCount, null, null, null); + this.isParticipating = isParticipating; + } +} diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeResponse.java index be40633..79e0390 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeResponse.java @@ -33,6 +33,9 @@ public class ChallengeResponse { @Schema(description = "성공률(백분율)", example = "85.5") private final double successRate; + @Schema(description = "성공한 참여자 수", example = "50") + private final int successCount; + @Schema(description = "참여자 수", example = "50") private final int participantCount; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ProofDetail.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/ProofDetail.java new file mode 100644 index 0000000..cbabba1 --- /dev/null +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/ProofDetail.java @@ -0,0 +1,25 @@ +package com.fledge.fledgeserver.challenge.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Schema(description = "인증 내역 상세 정보 DTO") +public class ProofDetail { + + @Schema(description = "인증 상태", example = "true") + private boolean status; + + @Schema(description = "인증 이미지 URL", example = "https://example.com/proof.jpg") + private String proofImageUrl; + + @Schema(description = "인증 설명", example = "하루 운동 인증합니다!") + private String description; + +} diff --git a/src/main/java/com/fledge/fledgeserver/challenge/entity/ChallengeProof.java b/src/main/java/com/fledge/fledgeserver/challenge/entity/ChallengeProof.java index c5c2b1c..0cd6572 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/entity/ChallengeProof.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/entity/ChallengeProof.java @@ -26,13 +26,16 @@ public class ChallengeProof { @Lob private String proofImageUrl; + private String proofDescription; + private boolean proofed; @Builder - public ChallengeProof(ChallengeParticipation participation, LocalDate proofDate, String proofImageUrl, boolean proofed) { + public ChallengeProof(ChallengeParticipation participation, LocalDate proofDate, String proofImageUrl, String proofDescription, boolean proofed) { this.participation = participation; this.proofDate = proofDate; this.proofImageUrl = proofImageUrl; + this.proofDescription = proofDescription; this.proofed = proofed; } diff --git a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeService.java b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeService.java index abef3ba..f23fa40 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeService.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeService.java @@ -1,5 +1,7 @@ package com.fledge.fledgeserver.challenge.service; +import com.fledge.fledgeserver.challenge.dto.ChallengeDetailResponse; +import com.fledge.fledgeserver.challenge.repository.ChallengeParticipationRepository; import com.fledge.fledgeserver.challenge.repository.ChallengeRepository; import com.fledge.fledgeserver.challenge.Enum.ChallengeCategory; import com.fledge.fledgeserver.challenge.Enum.ChallengeType; @@ -7,7 +9,10 @@ import com.fledge.fledgeserver.challenge.entity.Challenge; import com.fledge.fledgeserver.challenge.entity.OrganizationChallenge; import com.fledge.fledgeserver.challenge.entity.PartnershipChallenge; +import com.fledge.fledgeserver.common.utils.SecurityUtils; import com.fledge.fledgeserver.exception.CustomException; +import com.fledge.fledgeserver.exception.ErrorCode; +import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; @@ -19,13 +24,11 @@ import static com.fledge.fledgeserver.exception.ErrorCode.CHALLENGE_TYPE_INVALID; @Service +@RequiredArgsConstructor public class ChallengeService { private final ChallengeRepository challengeRepository; - - public ChallengeService(ChallengeRepository challengeRepository) { - this.challengeRepository = challengeRepository; - } + private final ChallengeParticipationRepository challengeParticipationRepository; public Page getChallenges(int page, int size, String type, List categories) { Sort.Direction direction = Sort.Direction.DESC; @@ -55,10 +58,31 @@ public Page getChallenges(int page, int size, String type, Li challenge.getType().name(), challenge.getDescription(), (double) challenge.getSuccessCount() / challenge.getParticipantCount(), + challenge.getSuccessCount(), challenge.getParticipantCount() )); } + + public ChallengeDetailResponse getChallengeById(Long challengeId) { + Challenge challenge = challengeRepository.findById(challengeId) + .orElseThrow(() -> new CustomException(ErrorCode.CHALLENGE_NOT_FOUND)); + + boolean isParticipating = SecurityUtils.isAuthenticated() && challengeParticipationRepository.existsByMemberIdAndChallengeId(SecurityUtils.getCurrentUserId(), challengeId); + + return new ChallengeDetailResponse( + challenge.getTitle(), + challenge.getLikeCount(), + challenge.getCategories(), + challenge.getType().name(), + challenge.getDescription(), + (double) challenge.getSuccessCount() / challenge.getParticipantCount(), + challenge.getSuccessCount(), + challenge.getParticipantCount(), + isParticipating + ); + } + public Page getPartnershipAndOrganizationChallenges(int page, int size, List categories) { Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "registrationDate")); @@ -76,10 +100,13 @@ public Page getPartnershipAndOrganizationChallenges(int page, challenge.getType().name(), challenge.getDescription(), (double) challenge.getSuccessCount() / challenge.getParticipantCount(), + challenge.getSuccessCount(), challenge.getParticipantCount(), challenge instanceof PartnershipChallenge ? ((PartnershipChallenge) challenge).getSupportContent() : ((OrganizationChallenge) challenge).getSupportContent(), challenge instanceof PartnershipChallenge ? ((PartnershipChallenge) challenge).getStartDate() : ((OrganizationChallenge) challenge).getStartDate(), challenge instanceof PartnershipChallenge ? ((PartnershipChallenge) challenge).getEndDate() : ((OrganizationChallenge) challenge).getEndDate() )); } + + } diff --git a/src/main/java/com/fledge/fledgeserver/common/utils/SecurityUtils.java b/src/main/java/com/fledge/fledgeserver/common/utils/SecurityUtils.java index 3d7efa7..01b99f0 100644 --- a/src/main/java/com/fledge/fledgeserver/common/utils/SecurityUtils.java +++ b/src/main/java/com/fledge/fledgeserver/common/utils/SecurityUtils.java @@ -81,4 +81,8 @@ public static Member checkAndGetCurrentUser(Long userId) { return getCurrentMember(); } + public static boolean isAuthenticated() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + return authentication != null && authentication.isAuthenticated() && !(authentication.getPrincipal() instanceof String); + } } diff --git a/src/main/java/com/fledge/fledgeserver/response/SuccessStatus.java b/src/main/java/com/fledge/fledgeserver/response/SuccessStatus.java index f66e5f8..762b235 100644 --- a/src/main/java/com/fledge/fledgeserver/response/SuccessStatus.java +++ b/src/main/java/com/fledge/fledgeserver/response/SuccessStatus.java @@ -54,7 +54,10 @@ public enum SuccessStatus { CHALLENGE_RETRIEVAL_SUCCESS(HttpStatus.OK, "챌린지 조회 성공"), CHALLENGE_PARTICIPATION_SUCCESS(HttpStatus.OK, "챌린지 참여 성공"), CHALLENGE_PROOF_UPLOAD_SUCCESS(HttpStatus.OK, "챌린지 인증 업로드 성공"), - CHALLENGE_UPDATE_SUCCESS(HttpStatus.NO_CONTENT, "챌린지 업데이트 성공"); + CHALLENGE_UPDATE_SUCCESS(HttpStatus.NO_CONTENT, "챌린지 업데이트 성공"), + CHALLENGE_PARTICIPANTS_RETRIEVED_SUCCESS(HttpStatus.OK, "챌린지 참여자 목록 조회에 성공했습니다."), + CHALLENGE_PROOFS_RETRIEVED_SUCCESS(HttpStatus.OK, "챌린지 인증 내역 조회에 성공했습니다."), + CHALLENGE_DETAILS_RETRIEVED_SUCCESS(HttpStatus.OK, "챌린지 상세 조회에 성공했습니다."); private final HttpStatus httpStatus; From 0909ddd1476bdc307e20bf989f2063d902c8945e Mon Sep 17 00:00:00 2001 From: gaguriee <74501631+gaguriee@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:06:34 +0900 Subject: [PATCH 4/7] =?UTF-8?q?CHORE=20:=20dto=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../challenge/controller/ChallengeController.java | 6 +++++- .../controller/PublicChallengeController.java | 4 +++- .../ChallengeParticipationRequest.java | 2 +- .../dto/{ => request}/ChallengeProofRequest.java | 2 +- .../{ => response}/ChallengeDetailResponse.java | 2 +- .../ChallengeParticipationResponse.java | 2 +- .../dto/{ => response}/ChallengeProofResponse.java | 2 +- .../dto/{ => response}/ChallengeResponse.java | 2 +- .../ChallengerParticipationPersonResponse.java | 2 +- .../{ => response}/MyChallengeProofResponse.java | 4 ++-- .../ProofDetailResponse.java} | 4 ++-- .../dto/{ => response}/TopParticipantResponse.java | 2 +- .../service/ChallengeParticipationService.java | 6 +++--- .../challenge/service/ChallengeProofService.java | 14 +++++++------- .../challenge/service/ChallengeService.java | 4 ++-- 15 files changed, 32 insertions(+), 26 deletions(-) rename src/main/java/com/fledge/fledgeserver/challenge/dto/{ => request}/ChallengeParticipationRequest.java (91%) rename src/main/java/com/fledge/fledgeserver/challenge/dto/{ => request}/ChallengeProofRequest.java (90%) rename src/main/java/com/fledge/fledgeserver/challenge/dto/{ => response}/ChallengeDetailResponse.java (93%) rename src/main/java/com/fledge/fledgeserver/challenge/dto/{ => response}/ChallengeParticipationResponse.java (95%) rename src/main/java/com/fledge/fledgeserver/challenge/dto/{ => response}/ChallengeProofResponse.java (95%) rename src/main/java/com/fledge/fledgeserver/challenge/dto/{ => response}/ChallengeResponse.java (96%) rename src/main/java/com/fledge/fledgeserver/challenge/dto/{ => response}/ChallengerParticipationPersonResponse.java (94%) rename src/main/java/com/fledge/fledgeserver/challenge/dto/{ => response}/MyChallengeProofResponse.java (81%) rename src/main/java/com/fledge/fledgeserver/challenge/dto/{ProofDetail.java => response/ProofDetailResponse.java} (87%) rename src/main/java/com/fledge/fledgeserver/challenge/dto/{ => response}/TopParticipantResponse.java (94%) diff --git a/src/main/java/com/fledge/fledgeserver/challenge/controller/ChallengeController.java b/src/main/java/com/fledge/fledgeserver/challenge/controller/ChallengeController.java index 13f9a0e..c06c18c 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/controller/ChallengeController.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/controller/ChallengeController.java @@ -1,6 +1,10 @@ package com.fledge.fledgeserver.challenge.controller; -import com.fledge.fledgeserver.challenge.dto.*; +import com.fledge.fledgeserver.challenge.dto.request.ChallengeParticipationRequest; +import com.fledge.fledgeserver.challenge.dto.request.ChallengeProofRequest; +import com.fledge.fledgeserver.challenge.dto.response.ChallengeParticipationResponse; +import com.fledge.fledgeserver.challenge.dto.response.ChallengeProofResponse; +import com.fledge.fledgeserver.challenge.dto.response.MyChallengeProofResponse; import com.fledge.fledgeserver.challenge.service.ChallengeParticipationService; import com.fledge.fledgeserver.challenge.service.ChallengeProofService; import com.fledge.fledgeserver.response.ApiResponse; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/controller/PublicChallengeController.java b/src/main/java/com/fledge/fledgeserver/challenge/controller/PublicChallengeController.java index e592d45..2fcfd91 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/controller/PublicChallengeController.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/controller/PublicChallengeController.java @@ -1,7 +1,9 @@ package com.fledge.fledgeserver.challenge.controller; import com.fledge.fledgeserver.challenge.Enum.ChallengeCategory; -import com.fledge.fledgeserver.challenge.dto.*; +import com.fledge.fledgeserver.challenge.dto.response.ChallengeResponse; +import com.fledge.fledgeserver.challenge.dto.response.ChallengerParticipationPersonResponse; +import com.fledge.fledgeserver.challenge.dto.response.TopParticipantResponse; import com.fledge.fledgeserver.challenge.service.ChallengeParticipationService; import com.fledge.fledgeserver.challenge.service.ChallengeService; import com.fledge.fledgeserver.response.ApiResponse; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeParticipationRequest.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/request/ChallengeParticipationRequest.java similarity index 91% rename from src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeParticipationRequest.java rename to src/main/java/com/fledge/fledgeserver/challenge/dto/request/ChallengeParticipationRequest.java index 9204df6..1c7f86a 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeParticipationRequest.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/request/ChallengeParticipationRequest.java @@ -1,4 +1,4 @@ -package com.fledge.fledgeserver.challenge.dto; +package com.fledge.fledgeserver.challenge.dto.request; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeProofRequest.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/request/ChallengeProofRequest.java similarity index 90% rename from src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeProofRequest.java rename to src/main/java/com/fledge/fledgeserver/challenge/dto/request/ChallengeProofRequest.java index 86f270d..3204148 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeProofRequest.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/request/ChallengeProofRequest.java @@ -1,4 +1,4 @@ -package com.fledge.fledgeserver.challenge.dto; +package com.fledge.fledgeserver.challenge.dto.request; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeDetailResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeDetailResponse.java similarity index 93% rename from src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeDetailResponse.java rename to src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeDetailResponse.java index f727b33..c9002e2 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeDetailResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeDetailResponse.java @@ -1,4 +1,4 @@ -package com.fledge.fledgeserver.challenge.dto; +package com.fledge.fledgeserver.challenge.dto.response; import com.fledge.fledgeserver.challenge.Enum.ChallengeCategory; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeParticipationResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeParticipationResponse.java similarity index 95% rename from src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeParticipationResponse.java rename to src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeParticipationResponse.java index 787b5c9..8b5fade 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeParticipationResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeParticipationResponse.java @@ -1,4 +1,4 @@ -package com.fledge.fledgeserver.challenge.dto; +package com.fledge.fledgeserver.challenge.dto.response; import com.fledge.fledgeserver.challenge.entity.ChallengeParticipation; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeProofResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeProofResponse.java similarity index 95% rename from src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeProofResponse.java rename to src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeProofResponse.java index 9ca33ab..9727323 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeProofResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeProofResponse.java @@ -1,4 +1,4 @@ -package com.fledge.fledgeserver.challenge.dto; +package com.fledge.fledgeserver.challenge.dto.response; import com.fledge.fledgeserver.challenge.entity.ChallengeProof; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeResponse.java similarity index 96% rename from src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeResponse.java rename to src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeResponse.java index 79e0390..17a0b69 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengeResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeResponse.java @@ -1,4 +1,4 @@ -package com.fledge.fledgeserver.challenge.dto; +package com.fledge.fledgeserver.challenge.dto.response; import com.fledge.fledgeserver.challenge.Enum.ChallengeCategory; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengerParticipationPersonResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengerParticipationPersonResponse.java similarity index 94% rename from src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengerParticipationPersonResponse.java rename to src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengerParticipationPersonResponse.java index 31460de..8647fa3 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/ChallengerParticipationPersonResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengerParticipationPersonResponse.java @@ -1,4 +1,4 @@ -package com.fledge.fledgeserver.challenge.dto; +package com.fledge.fledgeserver.challenge.dto.response; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/MyChallengeProofResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/MyChallengeProofResponse.java similarity index 81% rename from src/main/java/com/fledge/fledgeserver/challenge/dto/MyChallengeProofResponse.java rename to src/main/java/com/fledge/fledgeserver/challenge/dto/response/MyChallengeProofResponse.java index 9671ac8..482bf7c 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/MyChallengeProofResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/MyChallengeProofResponse.java @@ -1,4 +1,4 @@ -package com.fledge.fledgeserver.challenge.dto; +package com.fledge.fledgeserver.challenge.dto.response; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; @@ -19,5 +19,5 @@ public class MyChallengeProofResponse { private int totalProofs; @Schema(description = "현재 인증 내역 리스트") - private List proofDetails; + private List proofDetailResponses; } diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/ProofDetail.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ProofDetailResponse.java similarity index 87% rename from src/main/java/com/fledge/fledgeserver/challenge/dto/ProofDetail.java rename to src/main/java/com/fledge/fledgeserver/challenge/dto/response/ProofDetailResponse.java index cbabba1..82baa60 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/ProofDetail.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ProofDetailResponse.java @@ -1,4 +1,4 @@ -package com.fledge.fledgeserver.challenge.dto; +package com.fledge.fledgeserver.challenge.dto.response; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; @@ -11,7 +11,7 @@ @NoArgsConstructor @AllArgsConstructor @Schema(description = "인증 내역 상세 정보 DTO") -public class ProofDetail { +public class ProofDetailResponse { @Schema(description = "인증 상태", example = "true") private boolean status; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/TopParticipantResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/TopParticipantResponse.java similarity index 94% rename from src/main/java/com/fledge/fledgeserver/challenge/dto/TopParticipantResponse.java rename to src/main/java/com/fledge/fledgeserver/challenge/dto/response/TopParticipantResponse.java index e5daade..5ad748a 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/TopParticipantResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/TopParticipantResponse.java @@ -1,4 +1,4 @@ -package com.fledge.fledgeserver.challenge.dto; +package com.fledge.fledgeserver.challenge.dto.response; import com.fledge.fledgeserver.challenge.Enum.ChallengeCategory; import io.swagger.v3.oas.annotations.media.Schema; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeParticipationService.java b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeParticipationService.java index 00600c0..6ce099c 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeParticipationService.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeParticipationService.java @@ -1,14 +1,14 @@ package com.fledge.fledgeserver.challenge.service; import com.fledge.fledgeserver.canary.repository.CanaryProfileRepository; -import com.fledge.fledgeserver.challenge.dto.ChallengerParticipationPersonResponse; +import com.fledge.fledgeserver.challenge.dto.response.ChallengerParticipationPersonResponse; import com.fledge.fledgeserver.challenge.repository.ChallengeRepository; import com.fledge.fledgeserver.challenge.Enum.Frequency; -import com.fledge.fledgeserver.challenge.dto.TopParticipantResponse; +import com.fledge.fledgeserver.challenge.dto.response.TopParticipantResponse; import com.fledge.fledgeserver.challenge.entity.ChallengeParticipation; import com.fledge.fledgeserver.challenge.repository.ChallengeParticipationRepository; import com.fledge.fledgeserver.challenge.repository.ChallengeProofRepository; -import com.fledge.fledgeserver.challenge.dto.ChallengeParticipationResponse; +import com.fledge.fledgeserver.challenge.dto.response.ChallengeParticipationResponse; import com.fledge.fledgeserver.challenge.entity.Challenge; import com.fledge.fledgeserver.challenge.entity.ChallengeProof; import com.fledge.fledgeserver.common.utils.SecurityUtils; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeProofService.java b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeProofService.java index b90c00e..7066d44 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeProofService.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeProofService.java @@ -1,12 +1,12 @@ package com.fledge.fledgeserver.challenge.service; import com.fledge.fledgeserver.canary.repository.CanaryProfileRepository; -import com.fledge.fledgeserver.challenge.dto.MyChallengeProofResponse; -import com.fledge.fledgeserver.challenge.dto.ProofDetail; +import com.fledge.fledgeserver.challenge.dto.response.MyChallengeProofResponse; +import com.fledge.fledgeserver.challenge.dto.response.ProofDetailResponse; import com.fledge.fledgeserver.challenge.entity.ChallengeParticipation; import com.fledge.fledgeserver.challenge.repository.ChallengeParticipationRepository; import com.fledge.fledgeserver.challenge.repository.ChallengeProofRepository; -import com.fledge.fledgeserver.challenge.dto.ChallengeProofResponse; +import com.fledge.fledgeserver.challenge.dto.response.ChallengeProofResponse; import com.fledge.fledgeserver.challenge.entity.ChallengeProof; import com.fledge.fledgeserver.common.utils.SecurityUtils; import com.fledge.fledgeserver.exception.CustomException; @@ -58,16 +58,16 @@ public MyChallengeProofResponse getMyProofsByChallengeId(Long challengeId) { ChallengeParticipation participation = participationRepository.findByMemberIdAndChallengeId(member.getId(), challengeId) .orElseThrow(() -> new CustomException(ErrorCode.CHALLENGE_PARTICIPATION_NOT_FOUND)); - List proofDetails = proofRepository.findByParticipationId(participation.getId()).stream() - .map(proof -> new ProofDetail( + List proofDetailResponses = proofRepository.findByParticipationId(participation.getId()).stream() + .map(proof -> new ProofDetailResponse( proof.isProofed(), proof.getProofImageUrl(), proof.getProofDescription() )).collect(Collectors.toList()); - int totalProofs = proofDetails.size(); + int totalProofs = proofDetailResponses.size(); - return new MyChallengeProofResponse(totalProofs, proofDetails); + return new MyChallengeProofResponse(totalProofs, proofDetailResponses); } } diff --git a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeService.java b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeService.java index f23fa40..1993c7d 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeService.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/service/ChallengeService.java @@ -1,11 +1,11 @@ package com.fledge.fledgeserver.challenge.service; -import com.fledge.fledgeserver.challenge.dto.ChallengeDetailResponse; +import com.fledge.fledgeserver.challenge.dto.response.ChallengeDetailResponse; import com.fledge.fledgeserver.challenge.repository.ChallengeParticipationRepository; import com.fledge.fledgeserver.challenge.repository.ChallengeRepository; import com.fledge.fledgeserver.challenge.Enum.ChallengeCategory; import com.fledge.fledgeserver.challenge.Enum.ChallengeType; -import com.fledge.fledgeserver.challenge.dto.ChallengeResponse; +import com.fledge.fledgeserver.challenge.dto.response.ChallengeResponse; import com.fledge.fledgeserver.challenge.entity.Challenge; import com.fledge.fledgeserver.challenge.entity.OrganizationChallenge; import com.fledge.fledgeserver.challenge.entity.PartnershipChallenge; From acaeb72174eb2edc50c1a52f23f9514a4d46772e Mon Sep 17 00:00:00 2001 From: gaguriee <74501631+gaguriee@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:52:56 +0900 Subject: [PATCH 5/7] =?UTF-8?q?FEAT=20:=20Presigned=20url=20aspect,=20aop?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/ChallengeProofResponse.java | 3 + ...ChallengerParticipationPersonResponse.java | 3 + .../response/MyChallengeProofResponse.java | 3 + .../dto/response/ProofDetailResponse.java | 3 + .../common/aop/ApplyPresignedUrl.java | 11 +++ .../common/aop/PresignedUrlAspect.java | 80 +++++++++++++++++++ .../fledgeserver/file/FileController.java | 7 +- .../fledge/fledgeserver/file/FileService.java | 13 +-- .../support/service/SupportService.java | 9 +-- 9 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/fledge/fledgeserver/common/aop/ApplyPresignedUrl.java create mode 100644 src/main/java/com/fledge/fledgeserver/common/aop/PresignedUrlAspect.java diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeProofResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeProofResponse.java index 9727323..3dd5ac1 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeProofResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengeProofResponse.java @@ -1,6 +1,7 @@ package com.fledge.fledgeserver.challenge.dto.response; import com.fledge.fledgeserver.challenge.entity.ChallengeProof; +import com.fledge.fledgeserver.common.aop.ApplyPresignedUrl; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -10,6 +11,7 @@ @AllArgsConstructor @Getter +@ApplyPresignedUrl @Schema(description = "챌린지 인증 응답 DTO") public class ChallengeProofResponse { @@ -22,6 +24,7 @@ public class ChallengeProofResponse { @Schema(description = "인증 날짜", example = "2023-01-02") private LocalDate proofDate; + @ApplyPresignedUrl @Schema(description = "인증 이미지 URL", example = "http://example.com/proof.jpg") private String proofImageUrl; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengerParticipationPersonResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengerParticipationPersonResponse.java index 8647fa3..97b54a5 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengerParticipationPersonResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ChallengerParticipationPersonResponse.java @@ -1,5 +1,6 @@ package com.fledge.fledgeserver.challenge.dto.response; +import com.fledge.fledgeserver.common.aop.ApplyPresignedUrl; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -10,6 +11,7 @@ @Getter @Setter +@ApplyPresignedUrl @NoArgsConstructor @AllArgsConstructor @Schema(description = "챌린지 참여자 정보 응답 DTO") @@ -18,6 +20,7 @@ public class ChallengerParticipationPersonResponse { @Schema(description = "참여자 닉네임", example = "user123") private String nickname; + @ApplyPresignedUrl @Schema(description = "참여자 프로필 이미지 URL", example = "https://example.com/profile.jpg") private String profileImageUrl; diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/response/MyChallengeProofResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/MyChallengeProofResponse.java index 482bf7c..ecbb527 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/response/MyChallengeProofResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/MyChallengeProofResponse.java @@ -1,5 +1,6 @@ package com.fledge.fledgeserver.challenge.dto.response; +import com.fledge.fledgeserver.common.aop.ApplyPresignedUrl; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -12,12 +13,14 @@ @Setter @NoArgsConstructor @AllArgsConstructor +@ApplyPresignedUrl @Schema(description = "본인 챌린지 인증 내역 응답 DTO") public class MyChallengeProofResponse { @Schema(description = "필요한 인증 총 횟수", example = "7") private int totalProofs; + @ApplyPresignedUrl @Schema(description = "현재 인증 내역 리스트") private List proofDetailResponses; } diff --git a/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ProofDetailResponse.java b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ProofDetailResponse.java index 82baa60..3a76179 100644 --- a/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ProofDetailResponse.java +++ b/src/main/java/com/fledge/fledgeserver/challenge/dto/response/ProofDetailResponse.java @@ -1,5 +1,6 @@ package com.fledge.fledgeserver.challenge.dto.response; +import com.fledge.fledgeserver.common.aop.ApplyPresignedUrl; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Getter; @@ -10,12 +11,14 @@ @Setter @NoArgsConstructor @AllArgsConstructor +@ApplyPresignedUrl @Schema(description = "인증 내역 상세 정보 DTO") public class ProofDetailResponse { @Schema(description = "인증 상태", example = "true") private boolean status; + @ApplyPresignedUrl @Schema(description = "인증 이미지 URL", example = "https://example.com/proof.jpg") private String proofImageUrl; diff --git a/src/main/java/com/fledge/fledgeserver/common/aop/ApplyPresignedUrl.java b/src/main/java/com/fledge/fledgeserver/common/aop/ApplyPresignedUrl.java new file mode 100644 index 0000000..d6ee1e5 --- /dev/null +++ b/src/main/java/com/fledge/fledgeserver/common/aop/ApplyPresignedUrl.java @@ -0,0 +1,11 @@ +package com.fledge.fledgeserver.common.aop; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.TYPE, ElementType.FIELD}) +public @interface ApplyPresignedUrl { +} diff --git a/src/main/java/com/fledge/fledgeserver/common/aop/PresignedUrlAspect.java b/src/main/java/com/fledge/fledgeserver/common/aop/PresignedUrlAspect.java new file mode 100644 index 0000000..a4663cb --- /dev/null +++ b/src/main/java/com/fledge/fledgeserver/common/aop/PresignedUrlAspect.java @@ -0,0 +1,80 @@ +package com.fledge.fledgeserver.common.aop; + +import com.fledge.fledgeserver.file.FileService; +import com.fledge.fledgeserver.response.ApiResponse; +import lombok.RequiredArgsConstructor; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import java.lang.reflect.Field; +import java.util.Collection; +@Aspect +@Component +@RequiredArgsConstructor +public class PresignedUrlAspect { + + private final FileService fileService; + + @AfterReturning( + pointcut = "execution(* com.fledge.fledgeserver..controller.*.*(..))" + + " && (@annotation(org.springframework.web.bind.annotation.ResponseBody)" + + " || @target(org.springframework.web.bind.annotation.RestController))", + returning = "result" + ) + public void applyPresignedUrls(Object result) { + if (result instanceof ResponseEntity) { + ResponseEntity responseEntity = (ResponseEntity) result; + Object body = responseEntity.getBody(); + if (body instanceof ApiResponse) { + ApiResponse apiResponse = (ApiResponse) body; + Object data = apiResponse.getData(); + if (data != null) { + try { + processObject(data); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + } + } + + private void processObject(Object obj) throws IllegalAccessException { + if (obj == null) return; + + if (obj instanceof Collection) { + for (Object item : (Collection) obj) { + processObject(item); + } + } else { + processFields(obj); + } + } + + private void processFields(Object obj) throws IllegalAccessException { + Field[] fields = obj.getClass().getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + Object value = field.get(obj); + + if (value == null) continue; + + // String 클래스의 필드를 무시하도록 수정 + if (field.getType().equals(String.class) && field.isAnnotationPresent(ApplyPresignedUrl.class)) { + // @ApplyPresignedUrl이 붙은 String 필드 -> presigned URL로 변환 + String presignedUrl = fileService.getDownloadPresignedUrl((String) value); + field.set(obj, presignedUrl); + } else if (value instanceof Collection) { + // List나 Set 같은 컬렉션 타입 필드가 @ApplyPresignedUrl로 지정된 경우 + for (Object item : (Collection) value) { + processObject(item); + } + } else if (!field.getType().isPrimitive() && !field.getType().getPackageName().startsWith("java.")) { + // Java 표준 라이브러리 클래스의 필드 -> 재귀적으로 처리하지 않음 + processFields(value); + } + } + } + +} diff --git a/src/main/java/com/fledge/fledgeserver/file/FileController.java b/src/main/java/com/fledge/fledgeserver/file/FileController.java index 447ecf5..a9c9e30 100644 --- a/src/main/java/com/fledge/fledgeserver/file/FileController.java +++ b/src/main/java/com/fledge/fledgeserver/file/FileController.java @@ -1,8 +1,6 @@ package com.fledge.fledgeserver.file; -import com.fledge.fledgeserver.auth.dto.OAuthUserImpl; import com.fledge.fledgeserver.file.dto.PresignedUrlResponse; -import com.fledge.fledgeserver.member.dto.MemberResponse; import com.fledge.fledgeserver.response.ApiResponse; import com.fledge.fledgeserver.response.SuccessStatus; import io.swagger.v3.oas.annotations.Operation; @@ -10,7 +8,6 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; @@ -25,8 +22,8 @@ public class FileController { @Operation(summary = "프리사인드 URL 생성", description = "파일 업로드를 위한 프리사인드 URL을 생성합니다. 유효기간 15분 입니다.") @GetMapping("/presigned-url") public ResponseEntity> getPresignedUrl( - @Parameter(description = "파일 경로의 prefix", example = "images") @RequestParam(name = "prefix", required = false, defaultValue = "") String prefix, + @Parameter(description = "파일 경로의 prefix (이미지의 경우 images 필수)", example = "/images") @RequestParam(name = "prefix", required = true, defaultValue = "images") String prefix, @Parameter(description = "파일 이름", required = true, example = "example.txt") @RequestParam(name = "fileName") String fileName) { - return ApiResponse.success(SuccessStatus.FILE_RETRIEVAL_SUCCESS, fileService.getPresignedUrl(prefix, fileName)); + return ApiResponse.success(SuccessStatus.FILE_RETRIEVAL_SUCCESS, fileService.getUploadPresignedUrl(prefix, fileName)); } } diff --git a/src/main/java/com/fledge/fledgeserver/file/FileService.java b/src/main/java/com/fledge/fledgeserver/file/FileService.java index ad45420..4d56e27 100644 --- a/src/main/java/com/fledge/fledgeserver/file/FileService.java +++ b/src/main/java/com/fledge/fledgeserver/file/FileService.java @@ -27,7 +27,7 @@ public class FileService { private final AmazonS3 amazonS3; - public PresignedUrlResponse getPresignedUrl(String prefix, String originalFileName) { + public PresignedUrlResponse getUploadPresignedUrl(String prefix, String originalFileName) { String filePath = createPath(prefix, originalFileName); GeneratePresignedUrlRequest generatePresignedUrlRequest = getGeneratePresignedUrlRequest(bucket, filePath, HttpMethod.PUT); URL url = amazonS3.generatePresignedUrl(generatePresignedUrlRequest); @@ -35,11 +35,14 @@ public PresignedUrlResponse getPresignedUrl(String prefix, String originalFileNa return new PresignedUrlResponse(url.toString(), filePath); } - public String getFileUrl(String filePath) { - GeneratePresignedUrlRequest generatePresignedUrlRequest = getGeneratePresignedUrlRequest(bucket, filePath, HttpMethod.GET); - URL url = amazonS3.generatePresignedUrl(generatePresignedUrlRequest); + public String getDownloadPresignedUrl(String filePath) { + if (filePath != null && filePath.startsWith("images/")) { + GeneratePresignedUrlRequest generatePresignedUrlRequest = getGeneratePresignedUrlRequest(bucket, filePath, HttpMethod.GET); + URL url = amazonS3.generatePresignedUrl(generatePresignedUrlRequest); + return url.toString(); + } - return url.toString(); + return filePath; } private GeneratePresignedUrlRequest getGeneratePresignedUrlRequest(String bucket, String fileName, HttpMethod method) { diff --git a/src/main/java/com/fledge/fledgeserver/support/service/SupportService.java b/src/main/java/com/fledge/fledgeserver/support/service/SupportService.java index 06ca146..ae0d0c3 100644 --- a/src/main/java/com/fledge/fledgeserver/support/service/SupportService.java +++ b/src/main/java/com/fledge/fledgeserver/support/service/SupportService.java @@ -1,6 +1,5 @@ package com.fledge.fledgeserver.support.service; -import com.fledge.fledgeserver.exception.AuthException; import com.fledge.fledgeserver.exception.CustomException; import com.fledge.fledgeserver.exception.ErrorCode; import com.fledge.fledgeserver.file.FileService; @@ -97,7 +96,7 @@ record -> record.getMember().getNickname(), // 후원자 닉네임 supportPost.getPurchaseUrl(), supportPost.getPrice(), supportPost.getImages().stream() - .map(supportImage -> fileService.getFileUrl(supportImage.getImageUrl())) + .map(supportImage -> fileService.getDownloadPresignedUrl(supportImage.getImageUrl())) .toList(), supportPost.getExpirationDate(), supporterList @@ -188,7 +187,7 @@ public PostGetForUpdateResponse getSupportForUpdate(Long supportId, Long memberI String purchaseUrl = supportPost.getPurchaseUrl(); int price = supportPost.getPrice(); List images = supportPost.getImages().stream() - .map(supportImage -> fileService.getFileUrl(supportImage.getImageUrl())) + .map(supportImage -> fileService.getDownloadPresignedUrl(supportImage.getImageUrl())) .toList(); String promise = String.valueOf(supportPost.getPromise()); LocalDate expirationDate = supportPost.getExpirationDate(); @@ -262,7 +261,7 @@ public PostTotalPagingResponse pagingSupportPost(int page, String q, List deadlineApproachingPosts() { SupportImage supportImage = supportImageRepository.findFirstImageBySupportPostIdOrDefault(supportPostId); - String imageUrl = (supportImage != null) ? fileService.getFileUrl(supportImage.getImageUrl()) : null; // Set to null if no image found + String imageUrl = (supportImage != null) ? fileService.getDownloadPresignedUrl(supportImage.getImageUrl()) : null; // Set to null if no image found return new PostPagingResponse( supportPostId, From b17e92623cc53e61eee15332f4e06d83050fda4c Mon Sep 17 00:00:00 2001 From: gaguriee <74501631+gaguriee@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:56:53 +0900 Subject: [PATCH 6/7] =?UTF-8?q?REFACTOR=20:=20member=20dto=20aop=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fledge/fledgeserver/canary/dto/CanaryProfileRequest.java | 2 +- .../com/fledge/fledgeserver/member/dto/MemberResponse.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/fledge/fledgeserver/canary/dto/CanaryProfileRequest.java b/src/main/java/com/fledge/fledgeserver/canary/dto/CanaryProfileRequest.java index 495ffc3..5fb38ca 100644 --- a/src/main/java/com/fledge/fledgeserver/canary/dto/CanaryProfileRequest.java +++ b/src/main/java/com/fledge/fledgeserver/canary/dto/CanaryProfileRequest.java @@ -51,7 +51,7 @@ public class CanaryProfileRequest { @Size(max = 255, message = "우편번호는 최대 255자까지 입력 가능합니다.") private String zip; - @Schema(description = "보호종료확인서 경로", required = true, example = "/path/to/certificate") + @Schema(description = "보호종료확인서 경로", required = true, example = "files/certificate.pdf") @NotBlank(message = "보호종료확인서 경로는 필수입니다.") private String certificateFilePath; diff --git a/src/main/java/com/fledge/fledgeserver/member/dto/MemberResponse.java b/src/main/java/com/fledge/fledgeserver/member/dto/MemberResponse.java index ab24218..03cd3fa 100644 --- a/src/main/java/com/fledge/fledgeserver/member/dto/MemberResponse.java +++ b/src/main/java/com/fledge/fledgeserver/member/dto/MemberResponse.java @@ -1,11 +1,13 @@ package com.fledge.fledgeserver.member.dto; +import com.fledge.fledgeserver.common.aop.ApplyPresignedUrl; import com.fledge.fledgeserver.member.entity.Member; import com.fledge.fledgeserver.member.entity.Role; import lombok.Getter; import io.swagger.v3.oas.annotations.media.Schema; +@ApplyPresignedUrl @Getter @Schema(description = "회원 응답 DTO") public class MemberResponse { @@ -18,6 +20,7 @@ public class MemberResponse { @Schema(description = "회원 이메일", example = "email@example.com") private String email; + @ApplyPresignedUrl @Schema(description = "프로필 url", example = "http://t1.kakaocdn.net/account_images/default_profile.jpeg.twg.thumb.R640x640") private String profile; From 8e062afb9661b973a219710f4c90df02db26806a Mon Sep 17 00:00:00 2001 From: gaguriee <74501631+gaguriee@users.noreply.github.com> Date: Fri, 9 Aug 2024 22:11:36 +0900 Subject: [PATCH 7/7] =?UTF-8?q?BUG=20:=20aspect=20reflect.InaccessibleObje?= =?UTF-8?q?ctException=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/aop/PresignedUrlAspect.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/fledge/fledgeserver/common/aop/PresignedUrlAspect.java b/src/main/java/com/fledge/fledgeserver/common/aop/PresignedUrlAspect.java index a4663cb..12d4876 100644 --- a/src/main/java/com/fledge/fledgeserver/common/aop/PresignedUrlAspect.java +++ b/src/main/java/com/fledge/fledgeserver/common/aop/PresignedUrlAspect.java @@ -55,25 +55,28 @@ private void processObject(Object obj) throws IllegalAccessException { private void processFields(Object obj) throws IllegalAccessException { Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { - field.setAccessible(true); - Object value = field.get(obj); - - if (value == null) continue; - - // String 클래스의 필드를 무시하도록 수정 + // 필드가 String 타입이고 @ApplyPresignedUrl 어노테이션이 적용된 경우에만 접근 설정 if (field.getType().equals(String.class) && field.isAnnotationPresent(ApplyPresignedUrl.class)) { - // @ApplyPresignedUrl이 붙은 String 필드 -> presigned URL로 변환 - String presignedUrl = fileService.getDownloadPresignedUrl((String) value); - field.set(obj, presignedUrl); - } else if (value instanceof Collection) { + field.setAccessible(true); + Object value = field.get(obj); + + if (value != null) { + String presignedUrl = fileService.getDownloadPresignedUrl((String) value); + field.set(obj, presignedUrl); + } + } else if (field.getType().equals(Collection.class) && field.isAnnotationPresent(ApplyPresignedUrl.class)) { // List나 Set 같은 컬렉션 타입 필드가 @ApplyPresignedUrl로 지정된 경우 - for (Object item : (Collection) value) { - processObject(item); + Collection collection = (Collection) field.get(obj); + if (collection != null) { + for (Object item : collection) { + processObject(item); + } } - } else if (!field.getType().isPrimitive() && !field.getType().getPackageName().startsWith("java.")) { - // Java 표준 라이브러리 클래스의 필드 -> 재귀적으로 처리하지 않음 - processFields(value); } +// else if (!field.getType().isPrimitive() && !field.getType().getPackageName().startsWith("java.")) { +// // Java 표준 라이브러리 클래스의 필드 -> 재귀적으로 처리하지 않음 +// processFields(value); +// } } }