Skip to content

Commit

Permalink
Merge pull request #257 from HabitPay/feat/챌린지-개별-정보-api-개발#256
Browse files Browse the repository at this point in the history
Feat/챌린지 개별 정보 api 개발#256
  • Loading branch information
Han-Joon-Hyeok authored Oct 6, 2024
2 parents 6e24a1e + 994569c commit 6d58d1e
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 1 deletion.
42 changes: 42 additions & 0 deletions src/docs/asciidoc/api/challenge.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,48 @@ operation::challenge/get-challenge-details[snippets='http-request,http-response,

operation::challenge/get-challenge-details-not-found-exception[snippets='http-request,http-response,response-fields']

=== 챌린지 1회 실패당 벌금 조회

첼린지 1회 실패당 벌금을 조회합니다.

operation::challenge/get-challenge-fee-per-absence[snippets='http-request,http-response,response-fields']

==== 에러 응답

===== 챌린지가 존재하지 않는 경우 (404 Not Found)

존재하지 않는 챌린지를 조회한 경우입니다.

operation::challenge/get-challenge-fee-per-absence-not-found-exception[snippets='http-request,http-response,response-fields']

=== 챌린지 진행 기간 조회

첼린지 1회 실패당 벌금을 조회합니다.

operation::challenge/get-challenge-dates[snippets='http-request,http-response,response-fields']

==== 에러 응답

===== 챌린지가 존재하지 않는 경우 (404 Not Found)

존재하지 않는 챌린지를 조회한 경우입니다.

operation::challenge/get-challenge-dates-not-found-exception[snippets='http-request,http-response,response-fields']

=== 챌린지 참여 요일 조회

첼린지 참여 요일을 조회합니다.

operation::challenge/get-challenge-participating-days[snippets='http-request,http-response,response-fields']

==== 에러 응답

===== 챌린지가 존재하지 않는 경우 (404 Not Found)

존재하지 않는 챌린지를 조회한 경우입니다.

operation::challenge/get-challenge-participating-days-not-found-exception[snippets='http-request,http-response,response-fields']

=== 챌린지 생성

새로운 첼린지를 생성합니다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,21 @@ public SuccessResponse<ChallengeDetailsResponse> getChallengeDetails(@PathVariab
return challengeDetailsService.getChallengeDetails(id, user.getMember());
}

@GetMapping("/challenges/{id}/fees/absence")
public SuccessResponse<ChallengeFeePerAbsenceResponse> getChallengeFeePerAbsence(@PathVariable("id") Long id) {
return challengeDetailsService.getChallengeFeePerAbsence(id);
}

@GetMapping("/challenges/{id}/dates")
public SuccessResponse<ChallengeDatesResponse> getChallengeDates(@PathVariable("id") Long id) {
return challengeDetailsService.getChallengeDates(id);
}

@GetMapping("/challenges/{id}/participating-days")
public SuccessResponse<ChallengeParticipatingDaysResponse> getChallengeParticipatingDays(@PathVariable("id") Long id) {
return challengeDetailsService.getChallengeParticipatingDays(id);
}

@PostMapping("/challenges")
public SuccessResponse<ChallengeCreationResponse> createChallenge(@RequestBody ChallengeCreationRequest challengeCreationRequest,
@AuthenticationPrincipal CustomUserDetails user) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.habitpay.habitpay.domain.challenge.application;

import com.habitpay.habitpay.domain.challenge.domain.Challenge;
import com.habitpay.habitpay.domain.challenge.dto.ChallengeDatesResponse;
import com.habitpay.habitpay.domain.challenge.dto.ChallengeDetailsResponse;
import com.habitpay.habitpay.domain.challenge.dto.ChallengeFeePerAbsenceResponse;
import com.habitpay.habitpay.domain.challenge.dto.ChallengeParticipatingDaysResponse;
import com.habitpay.habitpay.domain.challengeenrollment.dao.ChallengeEnrollmentRepository;
import com.habitpay.habitpay.domain.challengeenrollment.domain.ChallengeEnrollment;
import com.habitpay.habitpay.domain.member.application.MemberSearchService;
import com.habitpay.habitpay.domain.member.domain.Member;
import com.habitpay.habitpay.global.config.aws.S3FileService;
import com.habitpay.habitpay.global.response.SuccessCode;
Expand Down Expand Up @@ -47,4 +49,31 @@ public SuccessResponse<ChallengeDetailsResponse> getChallengeDetails(Long challe
isMemberEnrolledInChallenge)
);
}

public SuccessResponse<ChallengeFeePerAbsenceResponse> getChallengeFeePerAbsence(Long challengeId) {
Challenge challenge = challengeSearchService.getChallengeById(challengeId);

return SuccessResponse.of(
SuccessCode.NO_MESSAGE,
ChallengeFeePerAbsenceResponse.from(challenge)
);
}

public SuccessResponse<ChallengeDatesResponse> getChallengeDates(Long challengeId) {
Challenge challenge = challengeSearchService.getChallengeById(challengeId);

return SuccessResponse.of(
SuccessCode.NO_MESSAGE,
ChallengeDatesResponse.from(challenge)
);
}

public SuccessResponse<ChallengeParticipatingDaysResponse> getChallengeParticipatingDays(Long challengeId) {
Challenge challenge = challengeSearchService.getChallengeById(challengeId);

return SuccessResponse.of(
SuccessCode.NO_MESSAGE,
ChallengeParticipatingDaysResponse.from(challenge)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.habitpay.habitpay.domain.challenge.dto;

import com.habitpay.habitpay.domain.challenge.domain.Challenge;
import lombok.Builder;
import lombok.Getter;

import java.time.ZonedDateTime;

@Getter
@Builder
public class ChallengeDatesResponse {

private ZonedDateTime startDate;
private ZonedDateTime endDate;

public static ChallengeDatesResponse from(Challenge challenge) {
return ChallengeDatesResponse.builder()
.startDate(challenge.getStartDate())
.endDate(challenge.getEndDate())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.habitpay.habitpay.domain.challenge.dto;

import com.habitpay.habitpay.domain.challenge.domain.Challenge;
import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class ChallengeFeePerAbsenceResponse {

private int feePerAbsence;

public static ChallengeFeePerAbsenceResponse from(Challenge challenge) {
return ChallengeFeePerAbsenceResponse.builder()
.feePerAbsence(challenge.getFeePerAbsence())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.habitpay.habitpay.domain.challenge.dto;

import com.habitpay.habitpay.domain.challenge.domain.Challenge;
import lombok.Builder;
import lombok.Getter;

import java.time.DayOfWeek;
import java.time.format.TextStyle;
import java.util.EnumSet;
import java.util.Locale;

@Getter
@Builder
public class ChallengeParticipatingDaysResponse {

private String[] participatingDays;

public static ChallengeParticipatingDaysResponse from(Challenge challenge) {
return ChallengeParticipatingDaysResponse.builder()
.participatingDays(extractDaysFromBits(challenge.getParticipatingDays()))
.build();
}

public static String[] extractDaysFromBits(int participatingDays) {
EnumSet<DayOfWeek> daysOfParticipatingDays = EnumSet.noneOf(DayOfWeek.class);

for (int bit = 0; bit <= 6; bit += 1) {
int todayBitPosition = 6 - bit;
if ((participatingDays & (1 << todayBitPosition)) != 0) {
daysOfParticipatingDays.add(DayOfWeek.of(bit + 1));
}
}

return daysOfParticipatingDays.stream()
.map(day -> day.getDisplayName(TextStyle.SHORT, Locale.KOREAN))
.toArray(String[]::new);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,177 @@ void getChallengeDetailsNotFoundException() throws Exception {
));
}

@Test
@WithMockOAuth2User
@DisplayName("챌린지 1회 실패당 벌금 조회")
void getChallengeFeePerAbsence() throws Exception {

// given
ChallengeFeePerAbsenceResponse challengeFeePerAbsenceResponse = ChallengeFeePerAbsenceResponse.builder()
.feePerAbsence(1000)
.build();

given(challengeDetailsService.getChallengeFeePerAbsence(anyLong()))
.willReturn(SuccessResponse.of(SuccessCode.NO_MESSAGE, challengeFeePerAbsenceResponse));

// when
ResultActions result = mockMvc.perform(get("/api/challenges/{id}/fees/absence", 1L)
.header(HttpHeaders.AUTHORIZATION, AUTHORIZATION_HEADER_PREFIX + "ACCESS_TOKEN"));

// then
result.andExpect(status().isOk())
.andDo(document("challenge/get-challenge-fee-per-absence",
requestHeaders(
headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰")
),
responseFields(
fieldWithPath("message").description("메세지"),
fieldWithPath("data.feePerAbsence").description("미참여 1회당 벌금")
)
));
}

@Test
@WithMockOAuth2User
@DisplayName("챌린지 1회 실패당 벌금 조회 예외처리 - 존재하지 않는 챌린지 (404 Not Found)")
void getChallengeFeePerAbsenceNotFoundException() throws Exception {

// given
given(challengeDetailsService.getChallengeFeePerAbsence(anyLong()))
.willThrow(new ChallengeNotFoundException(0L));

// when
ResultActions result = mockMvc.perform(get("/api/challenges/{id}/fees/absence", 0L)
.header(HttpHeaders.AUTHORIZATION, AUTHORIZATION_HEADER_PREFIX + "ACCESS_TOKEN"));

// then
result.andExpect(status().isNotFound())
.andDo(document("challenge/get-challenge-fee-per-absence-not-found-exception",
requestHeaders(
headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰")
),
responseFields(
fieldWithPath("code").description("오류 응답 코드"),
fieldWithPath("message").description("오류 메세지")
)
));
}

@Test
@WithMockOAuth2User
@DisplayName("챌린지 진행 기간 조회")
void getChallengeDates() throws Exception {

// given
ChallengeDatesResponse challengeDatesResponse = ChallengeDatesResponse.builder()
.startDate(ZonedDateTime.now())
.endDate(ZonedDateTime.now().plusDays(2))
.build();

given(challengeDetailsService.getChallengeDates(anyLong()))
.willReturn(SuccessResponse.of(SuccessCode.NO_MESSAGE, challengeDatesResponse));

// when
ResultActions result = mockMvc.perform(get("/api/challenges/{id}/dates", 1L)
.header(HttpHeaders.AUTHORIZATION, AUTHORIZATION_HEADER_PREFIX + "ACCESS_TOKEN"));

// then
result.andExpect(status().isOk())
.andDo(document("challenge/get-challenge-dates",
requestHeaders(
headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰")
),
responseFields(
fieldWithPath("message").description("메세지"),
fieldWithPath("data.startDate").description("챌린지 시작 날짜"),
fieldWithPath("data.endDate").description("챌린지 종료 날짜")
)
));
}

@Test
@WithMockOAuth2User
@DisplayName("챌린지 진행 기간 조회 예외처리 - 존재하지 않는 챌린지 (404 Not Found)")
void getChallengeDatesNotFoundException() throws Exception {

// given
given(challengeDetailsService.getChallengeDates(anyLong()))
.willThrow(new ChallengeNotFoundException(0L));

// when
ResultActions result = mockMvc.perform(get("/api/challenges/{id}/dates", 0L)
.header(HttpHeaders.AUTHORIZATION, AUTHORIZATION_HEADER_PREFIX + "ACCESS_TOKEN"));

// then
result.andExpect(status().isNotFound())
.andDo(document("challenge/get-challenge-dates-not-found-exception",
requestHeaders(
headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰")
),
responseFields(
fieldWithPath("code").description("오류 응답 코드"),
fieldWithPath("message").description("오류 메세지")
)
));
}

@Test
@WithMockOAuth2User
@DisplayName("챌린지 참여 요일 조회")
void getChallengeParticipatingDays() throws Exception {

// given
String[] participatingDays = {"월", "화"};
ChallengeParticipatingDaysResponse challengeParticipatingDaysResponse = ChallengeParticipatingDaysResponse.builder()
.participatingDays(participatingDays)
.build();

given(challengeDetailsService.getChallengeParticipatingDays(anyLong()))
.willReturn(SuccessResponse.of(SuccessCode.NO_MESSAGE, challengeParticipatingDaysResponse));

// when
ResultActions result = mockMvc.perform(get("/api/challenges/{id}/participating-days", 1L)
.header(HttpHeaders.AUTHORIZATION, AUTHORIZATION_HEADER_PREFIX + "ACCESS_TOKEN"));

// then
result.andExpect(status().isOk())
.andDo(document("challenge/get-challenge-participating-days",
requestHeaders(
headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰")
),
responseFields(
fieldWithPath("message").description("메세지"),
fieldWithPath("data.participatingDays").description("챌린지 참여 요일")
)
));
}

@Test
@WithMockOAuth2User
@DisplayName("챌린지 참여 요일 조회 예외처리 - 존재하지 않는 챌린지 (404 Not Found)")
void getChallengeParticipatingDaysNotFoundException() throws Exception {

// given
given(challengeDetailsService.getChallengeParticipatingDays(anyLong()))
.willThrow(new ChallengeNotFoundException(0L));

// when
ResultActions result = mockMvc.perform(get("/api/challenges/{id}/participating-days", 0L)
.header(HttpHeaders.AUTHORIZATION, AUTHORIZATION_HEADER_PREFIX + "ACCESS_TOKEN"));

// then
result.andExpect(status().isNotFound())
.andDo(document("challenge/get-challenge-participating-days-not-found-exception",
requestHeaders(
headerWithName(HttpHeaders.AUTHORIZATION).description("액세스 토큰")
),
responseFields(
fieldWithPath("code").description("오류 응답 코드"),
fieldWithPath("message").description("오류 메세지")
)
));
}

@Test
@WithMockOAuth2User
@DisplayName("챌린지 생성")
Expand Down

0 comments on commit 6d58d1e

Please sign in to comment.