-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BE] 기간 지정 팀플레이스 일정 조회 기능 구현 #95
The head ref may contain hidden characters: "feat/be/\uAE30\uAC04-\uC9C0\uC815-\uC77C\uC815-\uC870\uD68C-\uAE30\uB2A5-\uAD6C\uD604"
Changes from 5 commits
aea0308
62b33fd
4b91fbe
995286d
6af2427
e1c1117
63531d6
72826f7
0dcf8cf
610b508
5c63161
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
import org.springframework.transaction.annotation.Transactional; | ||
import team.teamby.teambyteam.schedule.application.dto.ScheduleRegisterRequest; | ||
import team.teamby.teambyteam.schedule.application.dto.ScheduleResponse; | ||
import team.teamby.teambyteam.schedule.application.dto.SchedulesResponse; | ||
import team.teamby.teambyteam.schedule.domain.Schedule; | ||
import team.teamby.teambyteam.schedule.domain.ScheduleRepository; | ||
import team.teamby.teambyteam.schedule.domain.Span; | ||
|
@@ -13,11 +14,20 @@ | |
import team.teamby.teambyteam.teamplace.domain.TeamPlaceRepository; | ||
import team.teamby.teambyteam.teamplace.exception.TeamPlaceException; | ||
|
||
import java.time.LocalDate; | ||
import java.time.LocalDateTime; | ||
import java.time.LocalTime; | ||
import java.time.temporal.TemporalAdjusters; | ||
import java.util.List; | ||
|
||
@Service | ||
@Transactional | ||
@RequiredArgsConstructor | ||
public class ScheduleService { | ||
|
||
private static final LocalTime START_TIME_OF_DAY = LocalTime.of(0, 0, 0); | ||
private static final LocalTime END_TIME_OF_DAY = LocalTime.of(23, 59, 59); | ||
|
||
private final ScheduleRepository scheduleRepository; | ||
private final TeamPlaceRepository teamPlaceRepository; | ||
|
||
|
@@ -61,4 +71,19 @@ private void validateScheduleOwnerTeam(final Long teamPlaceId, final Schedule sc | |
private boolean isNotScheduleOfTeam(final Long teamPlaceId, final Schedule schedule) { | ||
return !schedule.isScheduleOfTeam(teamPlaceId); | ||
} | ||
|
||
public SchedulesResponse findScheduleIn(final Long teamPlaceId, final int targetYear, final int targetMonth) { | ||
// TODO: 상의해보기 - 팀플레이스 소속 멤버 검증시 팀플레이스 아이디가 검증이 될 건데 해당 붑ㄴ에 대한 재 검증이 필요한가? | ||
checkTeamPlaceExist(teamPlaceId); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이부분 의견 남겨주시면 감사하겠습니다!!! |
||
|
||
final LocalDate startDate = LocalDate.of(targetYear, targetMonth, 1); | ||
final LocalDate endDAte = startDate.with(TemporalAdjusters.lastDayOfMonth()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분 변수명 endDAte -> endDate로 수정되어야 할 것 같습니다! |
||
final LocalDateTime startDateTime = LocalDateTime.of(startDate, START_TIME_OF_DAY); | ||
final LocalDateTime endDateTime = LocalDateTime.of(endDAte, END_TIME_OF_DAY); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분 잘 이해가 안돼서 코멘트로 설명해주시면 좋을 것 같아요! |
||
|
||
final List<Schedule> schedules = scheduleRepository | ||
.findAllByTeamPlaceInPeriod(teamPlaceId, startDateTime, endDateTime); | ||
|
||
return SchedulesResponse.of(schedules); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package team.teamby.teambyteam.schedule.application.dto; | ||
|
||
import team.teamby.teambyteam.schedule.domain.Schedule; | ||
|
||
import java.util.List; | ||
|
||
public record SchedulesResponse( | ||
List<ScheduleResponse> schedules | ||
) { | ||
public static SchedulesResponse of(final List<Schedule> schedules) { | ||
return new SchedulesResponse(schedules.stream() | ||
.map(ScheduleResponse::of) | ||
.toList() | ||
); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,22 @@ | ||
package team.teamby.teambyteam.schedule.domain; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
|
||
public interface ScheduleRepository extends JpaRepository<Schedule, Long> { | ||
|
||
@Query("SELECT s FROM Schedule s " + | ||
"WHERE s.teamPlaceId = :teamPlaceId " + | ||
"AND s.span.startDateTime < :lastDateTime " + | ||
"AND s.span.endDateTime > :firstDateTime" | ||
) | ||
List<Schedule> findAllByTeamPlaceInPeriod( | ||
Long teamPlaceId, | ||
LocalDateTime firstDateTime, | ||
LocalDateTime lastDateTime | ||
); | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,8 +17,10 @@ | |
import org.springframework.http.MediaType; | ||
import team.teamby.teambyteam.common.AcceptanceTest; | ||
import team.teamby.teambyteam.schedule.application.dto.ScheduleRegisterRequest; | ||
import team.teamby.teambyteam.schedule.application.dto.ScheduleResponse; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
@@ -39,7 +41,7 @@ public class ScheduleAcceptanceTest extends AcceptanceTest { | |
|
||
@Nested | ||
@DisplayName("팀플레이스 내 특정 일정 조회") | ||
class FindTest { | ||
class FindTeamPlaceSpecificSchedule { | ||
|
||
@Test | ||
@DisplayName("팀에서 아이디를 가지고 특정 일정을 조회한다.") | ||
|
@@ -88,6 +90,69 @@ void failGetScheduleWhichIsNot() { | |
} | ||
} | ||
|
||
@Nested | ||
@DisplayName("팀플래이스 내 기간 일정 조회 시") | ||
class FindTeamPlaceScheduleInPeriod { | ||
|
||
@Test | ||
@DisplayName("기간으로 조회 성공한다.") | ||
void success() { | ||
// given | ||
final Long teamPlaceId = 3L; | ||
final int year = 2023; | ||
final int month = 7; | ||
|
||
// when | ||
final ExtractableResponse<Response> response = requestTeamPlaceSchedulesInPeriod(teamPlaceId, year, month); | ||
final List<ScheduleResponse> schedules = response.jsonPath().getList("schedules", ScheduleResponse.class); | ||
|
||
//then | ||
assertSoftly(softly -> { | ||
softly.assertThat(response.statusCode()).isEqualTo(HttpStatus.OK.value()); | ||
softly.assertThat(schedules.get(0).title()).isEqualTo("3번 팀플 B"); | ||
softly.assertThat(schedules.get(1).title()).isEqualTo("3번 팀플 C"); | ||
softly.assertThat(schedules.get(2).title()).isEqualTo("3번 팀플 D"); | ||
}); | ||
} | ||
|
||
@Test | ||
@DisplayName("요청에 패스쿼리가 누락되면 조회에 실패한다.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 패스 쿼리가 뭔가요?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 날짜정보라도 표현 수정했습니다!! |
||
void failWithMissingQuery() { | ||
// given | ||
final Long teamPlaceId = 3L; | ||
final int month = 7; | ||
|
||
// when | ||
final ExtractableResponse<Response> response = requestTeamPlaceSchedulesInPeriod(teamPlaceId, null, month); | ||
|
||
//then | ||
assertThat(response.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); | ||
} | ||
|
||
@Test | ||
@DisplayName("기간 요쳥에 잘못된 형식으로 요쳥되면 조회에 실패한다.") | ||
void failWithWrongQuery() { | ||
// given | ||
final Long teamPlaceId = 3L; | ||
final String year = "y2023"; | ||
final int month = 7; | ||
|
||
// when | ||
final ExtractableResponse<Response> response = RestAssured.given().log().all() | ||
.header(new Header("Authorization", JWT_PREFIX + JWT_TOKEN)) | ||
.pathParam("teamPlaceId", teamPlaceId) | ||
.queryParam("year", year) | ||
.queryParam("month", month) | ||
.when().log().all() | ||
.get("/api/team-place/{teamPlaceId}/calendar/schedules") | ||
.then().log().all() | ||
.extract(); | ||
|
||
//then | ||
assertThat(response.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value()); | ||
} | ||
} | ||
|
||
@Nested | ||
@DisplayName("일정 등록 시") | ||
class RegisterSchedule { | ||
|
@@ -195,4 +260,16 @@ private ExtractableResponse<Response> requestSpecificSchedule(final Long schedul | |
.then().log().all() | ||
.extract(); | ||
} | ||
|
||
private ExtractableResponse<Response> requestTeamPlaceSchedulesInPeriod(final Long teamPlaceId, final Integer year, final Integer month) { | ||
return RestAssured.given().log().all() | ||
.header(new Header("Authorization", JWT_PREFIX + JWT_TOKEN)) | ||
.pathParam("teamPlaceId", teamPlaceId) | ||
.queryParam("year", year) | ||
.queryParam("month", month) | ||
.when().log().all() | ||
.get("/api/team-place/{teamPlaceId}/calendar/schedules") | ||
.then().log().all() | ||
.extract(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package team.teamby.teambyteam.schedule.domain; | ||
|
||
import org.assertj.core.api.SoftAssertions; | ||
import org.junit.jupiter.api.DisplayName; | ||
import org.junit.jupiter.api.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; | ||
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; | ||
import org.springframework.test.context.jdbc.Sql; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
|
||
|
||
@DataJpaTest | ||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) | ||
@Sql(value = {"/h2-reset-pk.sql", "/h2-data.sql"}) | ||
class ScheduleRepositoryTest { | ||
|
||
@Autowired | ||
private ScheduleRepository scheduleRepository; | ||
|
||
@Test | ||
@DisplayName("특정 기간 내 팀플레이스 일정을 조회한다.") | ||
void findTeamPlaceScheduleInRange() { | ||
// given | ||
final Long teamPlaceId = 3L; | ||
final LocalDateTime firstDateTime = LocalDateTime.of(2023, 7, 1, 0, 0); | ||
final LocalDateTime endDateTime = LocalDateTime.of(2023, 7, 31, 23, 59); | ||
|
||
// when | ||
final List<Schedule> schedules = scheduleRepository.findAllByTeamPlaceInPeriod(teamPlaceId, firstDateTime, endDateTime); | ||
|
||
//then | ||
SoftAssertions.assertSoftly(softly -> { | ||
softly.assertThat(schedules).hasSize(3); | ||
softly.assertThat(schedules.get(0).getTitle().getValue()).isEqualTo("3번 팀플 B"); | ||
softly.assertThat(schedules.get(1).getTitle().getValue()).isEqualTo("3번 팀플 C"); | ||
softly.assertThat(schedules.get(2).getTitle().getValue()).isEqualTo("3번 팀플 D"); | ||
}); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interceptor에서 검증이 된다고 하면 Service로 들어오기 전에 teamPlaceId가 오염될 수도 있다고 생각합니다!
예를 들면 Controller 단에서 조작된 teamPlaceId가 들어올 수도 있을 것 같습니다!
물론 이런 경우는 거의 없겠지만 가능성이 존재하니 중복 검증해도 괜찮다고 생각합니다!