Skip to content

Commit

Permalink
Merge pull request #38 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 b61dd82 + dda8e2d commit 85e005a
Show file tree
Hide file tree
Showing 16 changed files with 213 additions and 149 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.fledge.fledgeserver.challenge;

public class ChallengeConstants {

public static final String POPULAR_TYPE = "popular";
public static final String NEW_TYPE = "new";
public static final String SORT_BY_LIKE_COUNT = "likeCount";
public static final String SORT_BY_REGISTRATION_DATE = "registrationDate";

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.fledge.fledgeserver.challenge.Enum.ChallengeCategory;
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;
Expand Down Expand Up @@ -43,7 +42,7 @@ public ResponseEntity<ApiResponse<Page<ChallengeResponse>>> getChallenges(
return ApiResponse.success(SuccessStatus.CHALLENGE_RETRIEVAL_SUCCESS, challengeResponses);
}

@Operation(summary = "일반 챌린지 상세 조회", description = "일반 챌린지 ID를 통해 특정 챌린지의 상세 정보를 조회합니다.")
@Operation(summary = "챌린지 상세 조회", description = "일반 챌린지 ID를 통해 특정 챌린지의 상세 정보를 조회합니다.")
@GetMapping("/{challengeId}")
public ResponseEntity<ApiResponse<ChallengeResponse>> getChallengeById(
@Parameter(description = "챌린지 ID", example = "1")
Expand All @@ -69,8 +68,8 @@ public ResponseEntity<ApiResponse<Page<ChallengeResponse>>> getPartnershipAndOrg

@Operation(summary = "가장 성공률이 높은 참여자 목록 조회", description = "가장 성공률이 높은 참여자 상위 20명을 조회합니다.")
@GetMapping("/top-participants")
public ResponseEntity<ApiResponse<List<TopParticipantResponse>>> getTopParticipants() {
List<TopParticipantResponse> topParticipants = participationService.getTopParticipants(20);
public ResponseEntity<ApiResponse<List<ChallengerParticipationPersonResponse>>> getTopParticipants() {
List<ChallengerParticipationPersonResponse> topParticipants = participationService.getTopParticipants(20);
return ApiResponse.success(SuccessStatus.CHALLENGE_RETRIEVAL_SUCCESS, topParticipants);
}

Expand All @@ -82,6 +81,17 @@ public ResponseEntity<ApiResponse<List<ChallengerParticipationPersonResponse>>>
}


@Operation(summary = "다른 챌린지 둘러보기", description = "특정 챌린지와 같은 카테고리에 속한 챌린지들을 우선적으로 보여주고, 그 외에 다른 챌린지들을 랜덤하게 가져옴 (최대 16개)")
@GetMapping("/{challengeId}/explore")
public ResponseEntity<ApiResponse<List<ChallengeResponse>>> exploreOtherChallenges(
@Parameter(description = "챌린지 ID", example = "1")
@PathVariable Long challengeId) {

List<ChallengeResponse> challengeResponses = challengeService.exploreOtherChallenges(challengeId);

return ApiResponse.success(SuccessStatus.CHALLENGE_EXPLORE_SUCCESS, challengeResponses);
}

}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package com.fledge.fledgeserver.challenge.dto.response;

import com.fledge.fledgeserver.challenge.entity.ChallengeProof;
import com.fledge.fledgeserver.common.aop.ApplyPresignedUrl;
import com.fledge.fledgeserver.common.Interface.PresignedUrlApplicable;
import com.fledge.fledgeserver.file.FileService;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -11,9 +12,8 @@

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

@Schema(description = "챌린지 인증 ID", example = "1")
private Long id;
Expand All @@ -24,7 +24,6 @@ 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 All @@ -40,4 +39,11 @@ public ChallengeProofResponse(ChallengeProof proof) {
this.proofed = proof.isProofed();
}

@Override
public void applyPresignedUrls(FileService fileService) {
if (this.proofImageUrl != null) {
this.proofImageUrl = fileService.getDownloadPresignedUrl(this.proofImageUrl);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.fledge.fledgeserver.challenge.dto.response;

import com.fledge.fledgeserver.common.aop.ApplyPresignedUrl;
import com.fledge.fledgeserver.common.Interface.PresignedUrlApplicable;
import com.fledge.fledgeserver.file.FileService;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -11,25 +12,36 @@

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

@Schema(description = "참여자 ID", example = "1")
private Long memberId;

@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;
private long totalCount;

@Schema(description = "성공률(백분율)", example = "80.0")
private Double successRate;

@Schema(description = "자주 참여하는 챌린지 카테고리 목록", example = "[\"SELF_DEVELOPMENT\", \"FITNESS\"]")
@Schema(description = "자주 참여하는 챌린지 카테고리 목록 (최대 3개)", example = "[\"SELF_DEVELOPMENT\", \"FITNESS\"]")
private List<String> topCategories;

@Override
public void applyPresignedUrls(FileService fileService) {
if (this.profileImageUrl != null) {
this.profileImageUrl = fileService.getDownloadPresignedUrl(this.profileImageUrl);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.fledge.fledgeserver.challenge.dto.response;

import com.fledge.fledgeserver.common.aop.ApplyPresignedUrl;
import com.fledge.fledgeserver.common.Interface.PresignedUrlApplicable;
import com.fledge.fledgeserver.file.FileService;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -13,14 +14,21 @@
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ApplyPresignedUrl
@Schema(description = "본인 챌린지 인증 내역 응답 DTO")
public class MyChallengeProofResponse {
public class MyChallengeProofResponse implements PresignedUrlApplicable {

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

@ApplyPresignedUrl
@Schema(description = "현재 인증 내역 리스트")
private List<ProofDetailResponse> proofDetailResponses;

@Override
public void applyPresignedUrls(FileService fileService) {
if (this.proofDetailResponses != null) {
for (ProofDetailResponse proofDetail : proofDetailResponses) {
proofDetail.applyPresignedUrls(fileService);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.fledge.fledgeserver.challenge.dto.response;

import com.fledge.fledgeserver.common.aop.ApplyPresignedUrl;
import com.fledge.fledgeserver.common.Interface.PresignedUrlApplicable;
import com.fledge.fledgeserver.file.FileService;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Getter;
Expand All @@ -11,18 +12,22 @@
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ApplyPresignedUrl
@Schema(description = "인증 내역 상세 정보 DTO")
public class ProofDetailResponse {
public class ProofDetailResponse implements PresignedUrlApplicable {

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

@Override
public void applyPresignedUrls(FileService fileService) {
if (this.proofImageUrl != null) {
this.proofImageUrl = fileService.getDownloadPresignedUrl(this.proofImageUrl);
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

public interface ChallengeParticipationRepository extends JpaRepository<ChallengeParticipation, Long> {

@Query("SELECT p.member.id AS memberId, p.member.nickname AS nickname, COUNT(p) AS participationCount, SUM(CASE WHEN p.isSuccess = true THEN 1 ELSE 0 END) AS successCount, " +
@Query("SELECT p.member.id AS memberId, p.member.nickname AS nickname, p.member.profile AS profileImageUrl, COUNT(p) AS participationCount, SUM(CASE WHEN p.isSuccess = true THEN 1 ELSE 0 END) AS successCount, " +
"(SUM(CASE WHEN p.isSuccess = true THEN 1 ELSE 0 END) * 1.0 / COUNT(p)) AS successRate " +
"FROM ChallengeParticipation p " +
"GROUP BY p.member.id " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

Expand All @@ -17,4 +19,10 @@ public interface ChallengeRepository extends JpaRepository<Challenge, Long> {
Page<Challenge> findByTypeIn(List<ChallengeType> types, Pageable pageable);

Page<Challenge> findByTypeInAndCategoriesIn(List<ChallengeType> types, List<ChallengeCategory> categories, Pageable pageable);

List<Challenge> findTop16ByCategoriesInAndIdNot(List<ChallengeCategory> categories, Long challengeId);

@Query("SELECT c FROM Challenge c WHERE c.id <> :challengeId ORDER BY function('RAND')")
List<Challenge> findRandomChallengesExcludingId(@Param("challengeId") Long challengeId, Pageable pageable);

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
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.response.TopParticipantResponse;
import com.fledge.fledgeserver.challenge.entity.ChallengeParticipation;
import com.fledge.fledgeserver.challenge.repository.ChallengeParticipationRepository;
import com.fledge.fledgeserver.challenge.repository.ChallengeProofRepository;
Expand All @@ -20,6 +19,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.time.LocalDate;
import java.util.List;
import java.util.stream.Collectors;
Expand All @@ -32,6 +32,7 @@ public class ChallengeParticipationService {
private final ChallengeProofRepository proofRepository;
private final CanaryProfileRepository canaryProfileRepository;
private final ChallengeRepository challengeRepository;
private final DecimalFormat df = new DecimalFormat("#.0");

@Transactional
public ChallengeParticipationResponse participateInChallenge(Long memberId, Long challengeId, LocalDate startDate) {
Expand Down Expand Up @@ -100,21 +101,25 @@ private LocalDate getNextProofDate(LocalDate currentDate, Frequency frequency) {
}

@Transactional(readOnly = true)
public List<TopParticipantResponse> getTopParticipants(int limit) {
public List<ChallengerParticipationPersonResponse> getTopParticipants(int limit) {
PageRequest pageable = PageRequest.of(0, limit);

// TODO : 조회 쿼리 변경

List<Object[]> topParticipants = participationRepository.findTopParticipants(pageable);

return topParticipants.stream()
.map(row -> {
Long memberId = (Long) row[0];
String memberNickname = (String) row[1];
Long participationCount = (Long) row[2];
Long successCount = (Long) row[3];
Double successRate = ((Number) row[4]).doubleValue() * 100;
String profileImageUrl = (String) row[2];
Long participationCount = (Long) row[3];
Long successCount = (Long) row[4];
Double successRate = ((Number) row[5]).doubleValue() * 100;

List<String> topCategories = participationRepository.findTopCategoriesByMemberId(memberId);

return new TopParticipantResponse(memberId, memberNickname, participationCount, successCount, successRate, topCategories);
return new ChallengerParticipationPersonResponse(memberId, memberNickname, profileImageUrl, participationCount, successCount, successRate, topCategories);
})
.collect(Collectors.toList());
}
Expand Down Expand Up @@ -161,10 +166,12 @@ public List<ChallengerParticipationPersonResponse> getParticipantsByChallengeId(
List<String> topCategories = participationRepository.findTopCategoriesByMemberId(member.getId());

return new ChallengerParticipationPersonResponse(
member.getId(),
member.getNickname(),
member.getProfile(),
successCount,
totalParticipation,
Double.parseDouble(df.format((double) successCount / totalParticipation)),
topCategories
);
}).collect(Collectors.toList());
Expand Down
Loading

0 comments on commit 85e005a

Please sign in to comment.