Skip to content

Commit

Permalink
Merge pull request #37 from K-Hackathon-Fledge/35-feature-challenge-d…
Browse files Browse the repository at this point in the history
…etail

35 feature challenge detail
  • Loading branch information
gaguriee authored Aug 9, 2024
2 parents 325c55b + 8e062af commit b61dd82
Show file tree
Hide file tree
Showing 27 changed files with 386 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
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.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.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
Expand All @@ -42,6 +40,13 @@ public ResponseEntity<ApiResponse<ChallengeProofResponse>> uploadProof(
return ApiResponse.success(SuccessStatus.CHALLENGE_PROOF_UPLOAD_SUCCESS, response);
}

@Operation(summary = "챌린지 인증 내역 조회", description = "특정 챌린지에 대해 사용자의 인증 내역을 조회합니다.")
@GetMapping("/{challengeId}/my-proof")
public ResponseEntity<ApiResponse<MyChallengeProofResponse>> getMyChallengeProofs(@PathVariable Long challengeId) {
MyChallengeProofResponse response = proofService.getMyProofsByChallengeId(challengeId);
return ApiResponse.success(SuccessStatus.CHALLENGE_PROOFS_RETRIEVED_SUCCESS, response);
}

}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
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.ChallengeProofService;
import com.fledge.fledgeserver.challenge.service.ChallengeService;
import com.fledge.fledgeserver.response.ApiResponse;
import com.fledge.fledgeserver.response.SuccessStatus;
Expand All @@ -26,7 +27,7 @@ public class PublicChallengeController {
private final ChallengeService challengeService;
private final ChallengeParticipationService participationService;

@Operation(summary = "일반 챌린지 조회", description = "좋아요 수 또는 등록일로 정렬된 챌린지 리스트를 조회합니다. 일반 챌린지만 포함됩니다.")
@Operation(summary = "일반 챌린지 리스트 조회", description = "좋아요 수 또는 등록일로 정렬된 챌린지 리스트를 조회합니다. 일반 챌린지만 포함됩니다.")
@GetMapping
public ResponseEntity<ApiResponse<Page<ChallengeResponse>>> getChallenges(
@Parameter(example = "0")
Expand All @@ -42,6 +43,16 @@ public ResponseEntity<ApiResponse<Page<ChallengeResponse>>> getChallenges(
return ApiResponse.success(SuccessStatus.CHALLENGE_RETRIEVAL_SUCCESS, challengeResponses);
}

@Operation(summary = "일반 챌린지 상세 조회", description = "일반 챌린지 ID를 통해 특정 챌린지의 상세 정보를 조회합니다.")
@GetMapping("/{challengeId}")
public ResponseEntity<ApiResponse<ChallengeResponse>> 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<ApiResponse<Page<ChallengeResponse>>> getPartnershipAndOrganizationChallenges(
Expand All @@ -63,6 +74,14 @@ public ResponseEntity<ApiResponse<List<TopParticipantResponse>>> getTopParticipa
return ApiResponse.success(SuccessStatus.CHALLENGE_RETRIEVAL_SUCCESS, topParticipants);
}

@Operation(summary = "챌린지 참여자 목록 조회", description = "특정 챌린지에 참여 중인 사용자들의 목록을 조회합니다.")
@GetMapping("/{challengeId}/participants")
public ResponseEntity<ApiResponse<List<ChallengerParticipationPersonResponse>>> getChallengeParticipants(@PathVariable Long challengeId) {
List<ChallengerParticipationPersonResponse> participants = participationService.getParticipantsByChallengeId(challengeId);
return ApiResponse.success(SuccessStatus.CHALLENGE_PARTICIPANTS_RETRIEVED_SUCCESS, participants);
}


}


Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.fledge.fledgeserver.challenge.dto.response;

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<ChallengeCategory> 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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.fledge.fledgeserver.challenge.dto;
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;
Expand All @@ -10,6 +11,7 @@

@AllArgsConstructor
@Getter
@ApplyPresignedUrl
@Schema(description = "챌린지 인증 응답 DTO")
public class ChallengeProofResponse {

Expand All @@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@ApplyPresignedUrl
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "챌린지 참여자 정보 응답 DTO")
public class ChallengerParticipationPersonResponse {

@Schema(description = "참여자 닉네임", example = "user123")
private String nickname;

@ApplyPresignedUrl
@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<String> topCategories;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.util.List;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ApplyPresignedUrl
@Schema(description = "본인 챌린지 인증 내역 응답 DTO")
public class MyChallengeProofResponse {

@Schema(description = "필요한 인증 총 횟수", example = "7")
private int totalProofs;

@ApplyPresignedUrl
@Schema(description = "현재 인증 내역 리스트")
private List<ProofDetailResponse> proofDetailResponses;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
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;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@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;

@Schema(description = "인증 설명", example = "하루 운동 인증합니다!")
private String description;

}
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.data.repository.query.Param;

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

public interface ChallengeParticipationRepository extends JpaRepository<ChallengeParticipation, Long> {

Expand All @@ -26,4 +27,15 @@ public interface ChallengeParticipationRepository extends JpaRepository<Challeng
"ORDER BY COUNT(p.id) DESC " +
"LIMIT 3", nativeQuery = true)
List<String> findTopCategoriesByMemberId(@Param("memberId") Long memberId);

Optional<ChallengeParticipation> findByMemberIdAndChallengeId(Long memberId, Long challengeId);

List<ChallengeParticipation> 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);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package com.fledge.fledgeserver.challenge.service;

import com.fledge.fledgeserver.canary.repository.CanaryProfileRepository;
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;
Expand Down Expand Up @@ -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));

Expand Down Expand Up @@ -145,5 +150,24 @@ public void checkMissedProofs() {
}
}
}

@Transactional(readOnly = true)
public List<ChallengerParticipationPersonResponse> getParticipantsByChallengeId(Long challengeId) {
List<ChallengeParticipation> 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<String> topCategories = participationRepository.findTopCategoriesByMemberId(member.getId());

return new ChallengerParticipationPersonResponse(
member.getNickname(),
member.getProfile(),
successCount,
totalParticipation,
topCategories
);
}).collect(Collectors.toList());
}
}

Loading

0 comments on commit b61dd82

Please sign in to comment.