Skip to content

켈리 1단계 PR 제출합니다.! #7

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

Open
wants to merge 71 commits into
base: kelly6bf
Choose a base branch
from

Conversation

kelly6bf
Copy link

@kelly6bf kelly6bf commented May 2, 2024

No description provided.

kelly6bf added 30 commits April 30, 2024 14:40
기존 200 응답을 201로 변경함.
Copy link

@leegwichan leegwichan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

켈리! 커찬이야~

시간이 없어서 내 코드와 달랐던 부분 위주로 코멘트 남겨봤어!
질문도 달아놨으니까 여유있을 떄 코멘트 남겨줘!
(마이그레이션 한 코드 빼고 보는 걸 깜박함...)

Comment on lines +14 to +20

### 테마 전체 조회

```http request
GET http://localhost:8080/themes
Content-Type: application/json
```

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API 명세서 👍 👍 👍

기왕 추가할 꺼면, HTTP Response까지 추가했으면 어떨까?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

각 도메인 (예약, 시간, 테마) 별로 Controller를 나누어보는 건 어때?

하나의 파일에서 너무 많은 엔트포인트를 관리하지 않나 싶어

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오우 동의합니다

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

도메인 객체 👍 👍 👍

Comment on lines +11 to +17
public static ReservationTimeAvailabilities of(final List<ReservationTime> reservationTimes, final List<Reservation> reservations) {
final Map<ReservationTime, Boolean> reservationTimeAvailabilities = new HashMap<>();
reservationTimes.forEach(reservationTime -> reservationTimeAvailabilities.put(
reservationTime, isTimeAvailable(reservations, reservationTime)));

return new ReservationTimeAvailabilities(reservationTimeAvailabilities);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
public static ReservationTimeAvailabilities of(final List<ReservationTime> reservationTimes, final List<Reservation> reservations) {
final Map<ReservationTime, Boolean> reservationTimeAvailabilities = new HashMap<>();
reservationTimes.forEach(reservationTime -> reservationTimeAvailabilities.put(
reservationTime, isTimeAvailable(reservations, reservationTime)));
return new ReservationTimeAvailabilities(reservationTimeAvailabilities);
}
public static ReservationTimeAvailabilities of(final List<ReservationTime> reservationTimes, final List<Reservation> reservations) {
final Map<ReservationTime, Boolean> reservationTimeAvailabilities = new HashMap<>();
reservationTimes.forEach(reservationTime ->
reservationTimeAvailabilities.put(reservationTime, isTimeAvailable(reservations, reservationTime)));
return new ReservationTimeAvailabilities(reservationTimeAvailabilities);
}

이게 가독성이 더 좋지 않을까 싶어.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 동의합니다

Comment on lines 12 to 18
public static Theme of(final String name, final String description, final String thumbnail) {
return new Theme(null, new ThemeName(name), new ThemeDescription(description), thumbnail);
}

public static Theme of(final Long id, final String name, final String description, final String thumbnail) {
return new Theme(id, new ThemeName(name), new ThemeDescription(description), thumbnail);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

인자에만 final을 사용한 이유는? (여기도 final 광인인가요?)

Comment on lines 12 to 20
@ExceptionHandler
protected ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}

@ExceptionHandler
protected ResponseEntity<ErrorResponse> handleNoSuchElementException(NoSuchElementException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 접근 제어자가 protected 인 이유는?
  2. 아래처럼 묶어서 사용해도 되지 않나요?
Suggested change
@ExceptionHandler
protected ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}
@ExceptionHandler
protected ResponseEntity<ErrorResponse> handleNoSuchElementException(NoSuchElementException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}
@ExceptionHandler({IllegalArgumentException.class, NoSuchElementException.class})
protected ResponseEntity<ErrorResponse> handleIllegalArgumentException(RuntimeException e) {
return ResponseEntity.badRequest().body(new ErrorResponse(e.getMessage()));
}

Comment on lines 28 to 36
final String sql = "SELECT "
+ "r.id as reservation_id, r.name as reservation_name, r.date as reservation_date, "
+ "rt.id as time_id, rt.start_at as reservation_time, "
+ "th.id as theme_id, th.name as theme_name, th.description as theme_description, th.thumbnail as theme_thumbnail "
+ "FROM reservation as r "
+ "inner join reservation_time as rt "
+ "on r.time_id = rt.id "
+ "inner join theme as th "
+ "on r.theme_id = th.id";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FROM 만 대문자인거 불~편

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SELECT도 대문자 👀

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

각 테스트가 동일한 데이터를 사용하게 된다면, 모든 테스트가 schema.sql에 종속되겠네요?
이것에 대해서는 어떻게 생각해?

Comment on lines -32 to +40
<!-- <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown"-->
<!-- <a class="nav-link dropdown-toggle" href="#" themeId="navbarDropdown" role="button" data-toggle="dropdown"-->
<!-- aria-haspopup="true" aria-expanded="false">-->
<!-- <img class="profile-image" src="/image/default-profile.png" alt="Profile">-->
<!-- <span id="profile-name">Profile</span> &lt;!&ndash; 프로필 이름을 넣을 span 추가 &ndash;&gt;-->
<!-- <span themeId="profile-name">Profile</span> &lt;!&ndash; 프로필 이름을 넣을 span 추가 &ndash;&gt;-->
<!-- </a>-->
<!-- <div class="dropdown-menu" aria-labelledby="navbarDropdown">-->
<!-- <a class="dropdown-item" href="/reservation-mine">My Reservation</a>-->
<!-- <div class="dropdown-divider"></div>-->
<!-- <a class="dropdown-item" href="#" id="logout-btn">Logout</a>-->
<!-- <a class="dropdown-item" href="#" themeId="logout-btn">Logout</a>-->

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTML에서 id가 뭐하는 것인지 한번 알아봐야 할것 같은데?

Comment on lines 9 to 23
public interface ReservationRepository {
List<Reservation> findAll();

Optional<Reservation> findById(Long reservationId);

Reservation save(Reservation reservation);

void deleteById(Long reservationId);

boolean existByDateAndTimeIdAndThemeId(LocalDate date, Long timeId, Long themeId);

boolean existByTimeId(Long reservationTimeId);

List<Reservation> findAllByDateAndThemeId(LocalDate date, Long themeId);
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interface를 도입한 근거는? 구현체는 H2밖에 없는뎁

Copy link
Member

@hyxrxn hyxrxn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

잘 읽었습니닷
다음 단계도 화이팅!

Comment on lines +3 to +11
- [X] 기존 API 입력값 검증 기능
- [X] 유저 페이지 라우팅 기능
- [X] 테마 도메인 추가
- [X] 테마 전체 조회 기능
- [X] 테마 추가 기능
- [X] 테마 삭제 기능
- [X] 사용자 예약 가능 시간 조회 기능
- [X] 사용자 페이지 방탈출 예약 기능
- [X] 인기 테마 조회 기능
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 미션 1단계가 예외 처리에 관한 내용이었으니 어떨 때 예외라고 생각했는지 함께 정리해주면 더 알아보기 좋을 것 같아요!

Comment on lines 47 to 48
return ResponseEntity.created(URI.create("/reservations/" + savedReservation.getId()))
.body(ReservationResponse.from(savedReservation));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로빈에게도 남긴 질문인데....

지금은 바디만 필요한 상태인데 URI까지 담아서 리턴하는 이유가 있을까요?

@ResponseStatus(HttpStatus.CREATED) 를 사용하면 ResponseEntity 없이도 201을 넘길 수 있답니닷...!
저는 이번에 알아서 이걸 사용해봤는데... 켈리는 알고 있지만 안썼을 수도 있겠다 싶어서 궁금하네용

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오우 동의합니다

Comment on lines 105 to 107
public Theme saveTheme(final SaveThemeRequest saveThemeRequest) {
return themeRepository.save(saveThemeRequest.toTheme());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 request를 받는 만큼 response를 돌려주는게 서비스의 역할이라고 생각해요.
켈리는 도메인을 리턴하고 컨트롤러가 response로 변환하는 역할을 가지고 있는 것 같은데, 따로 이유가 있나요?

Comment on lines 109 to 113
public void deleteTheme(final Long themeId) {
validateThemeExist(themeId);

themeRepository.deleteById(themeId);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예약이 존재하는 시간을 삭제하려고 하면 안내 메시지가 오는데요, 예약이 존재하는 테마를 삭제하려고 하면 그냥 404인 것 같네요


private final Map<ReservationTime, Boolean> values;

public static ReservationTimeAvailabilities of(final List<ReservationTime> reservationTimes, final List<Reservation> reservations) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 한 줄이... 너무 길어요 ㅠ

Comment on lines +11 to +17
public static ReservationTimeAvailabilities of(final List<ReservationTime> reservationTimes, final List<Reservation> reservations) {
final Map<ReservationTime, Boolean> reservationTimeAvailabilities = new HashMap<>();
reservationTimes.forEach(reservationTime -> reservationTimeAvailabilities.put(
reservationTime, isTimeAvailable(reservations, reservationTime)));

return new ReservationTimeAvailabilities(reservationTimeAvailabilities);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 동의합니다

Comment on lines 14 to 18
private void validateValue(final String value) {
if (value == null || value.isEmpty() || value.length() > MAXIMUM_ENABLE_NAME_LENGTH) {
throw new IllegalArgumentException("테마 설명은 1글자 이상 80글자 이하여야 합니다.");
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

설명 검증을 한 것은 좋은데요....!
isBlank가 아니라 isEmpty여서...
테마 제목과 설명과 썸네일에 띄어쓰기만 입력해도 등록이 되네요 ㅠ
의도한 것은 아니겠죠...?!

final MapSqlParameterSource param = new MapSqlParameterSource()
.addValue("reservationTimeId", reservationTimeId);

return Boolean.TRUE.equals(template.queryForObject(sql, param, Boolean.class));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이런 비교 방식이 있군요!

Comment on lines 33 to 62
INSERT INTO theme(name, description, thumbnail)
VALUES ('테바와 비밀친구', '나랑.. 비밀친구할래..?', '테바 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('켈리의 댄스교실', '켈켈켈켈켈', '켈리 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('우테코 탈출하기', '우테코를... 탈출..하자..!', '우테코 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('네오의 두근두근 피드백 강의', '??? : 네오가 setter 쓰라고 했는데요?', '분노하는 네오 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('리사의 소프트 교육', '에궁..ㅜㅜ', '공감하는 리사 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('신천직화 탈출하기', '저희 3인분 시켰는데 왜 계란말이 안주세요?', '제육 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('장미상가 탈출하기', '여기 A동 아니에요?', '장미상가 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('페드로의 주먹', '페급~ (페드로 급이라는 뜻~)', '페드로 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('사물함 탈취하기', '니 사물함 쩔더라 ㅋ', '사물함 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('아루의 입기타', '뚜루루루룰루루루룰', '아루 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('이든의 프로틴 쉐이크 제작 강의', '내 단백질 어디있죠?', '이든 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('솔라의 솔라빔', '자라나라 머리머리!', '솔라 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('포비의 긴급 포수타', '포비는 크루들에게 실망했다.', '포비 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('브리와 솔라의 페어프로그래밍 연극', '... 이거 이렇게 짜는거 맞아요?', '훈훈한 브리와 솔라 사진');
INSERT INTO theme(name, description, thumbnail)
VALUES ('레디의 코드리뷰', '아씨 깜짝아! 내 코드인줄 알았네 (제제의 코드를 보며)', '레디 사진');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋㅋㅋㅋㅋ 실행해보고 재밌었어요

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아니 레디의 코드리뷰 뭔데 ㅋㅋㅋㅋ

kelly6bf added 27 commits May 4, 2024 21:28
기존 삭제전 데이터 존재 여부를 조회하는 로직을 제거하고, 삭제된 데이터의 개수를 토대로 예외를 발생시키도록 로직을 수정함.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants