-
Notifications
You must be signed in to change notification settings - Fork 82
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[1 - 2단계 방탈출 예약 대기] 에버(손채영) 미션 제출합니다. (#72)
* migrate previous code * refactor(all): JPA 전환 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * feat(client): 자신의 예약 조회 페이지 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * feat(PageController): 자신의 예약 조회 페이지 반환 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * feat(ReservationController): 자신의 예약 조회 API Co-authored-by: hyxrxn <gpfls981220@gmail.com> * refactor(Member): 불필요한 생성자 삭제 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * refactor(MemberRepository): 불필요한 메서드 삭제 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * refactor(Member): 리턴 타입 스트링으로 통일 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * refactor(Theme): 불필요한 생성자 삭제 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * test(ReservationRepository): 테스트 보완 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * test(ReservationRepository): 특정 멤버 예약 조회 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * refactor(ReservationTimeDto): 주생성자 활용 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * test(ReservationService): 테스트 보완 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * refactor(test): assertAll 활용 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * test(ReservationController): 자신의 예약 조회 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * docs(README): 기능 구현사항 반영 Co-authored-by: hyxrxn <gpfls981220@gmail.com> * fix(model): 엔티티의 필드 검증 * chore(properties): SQL 쿼리 파라미터 활성화 * refactor(Reservation): 조인 시 지연 로딩 * refactor(Reservation): 필드에 null 들어가지 않도록 * refactor(member): Member 클래스 내부에서 사용되는 클래스 이름 변경 * refactor(model): PK를 통해 객체의 동등성 비교하도록 * refactor(repository): 불필요한 어노테이션 삭제 * test(ReservationService): 현재 시간 저장 로직 위치 이동 * style(all): 불필요한 import문 삭제 * chore(properties): transaction 로그 추가 * refactor(model): PK 타입 원시 타입에서 참조 타입으로 변경 * refactor(model): 불필요한 생성자 제거 및 형식 통일 * fix(ReservationServiceTest): 나노초로 인한 에러 해결 * refactor(Reservation): 불필요한 로직 제거 * style(ThemeServiceTest): 불필요한 import문 삭제 --------- Co-authored-by: hyxrxn <gpfls981220@gmail.com>
- Loading branch information
Showing
107 changed files
with
6,553 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
.gitmessage.txt | ||
|
||
HELP.md | ||
.gradle | ||
build/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
## 기능 요구사항 | ||
|
||
### 예외 처리 | ||
- [x] 시간 생성 시 시작 시간에 유효하지 않은 값이 입력되었을 때 | ||
- [x] null, "", HH:mm이 아닌 경우 | ||
- [x] 사용자의 예약 생성 시 날짜, 시간 id, 테마 id에 유효하지 않은 값이 입력 되었을 때 | ||
- [x] 날짜: null, "", yyyy-MM-dd이 아닌 경우 | ||
- [x] 시간 id: null, 1 이상이 아닌 경우 | ||
- [x] 테마 id: null, 1 이상이 아닌 경우 | ||
- [x] 관리자의 예약 생성 시 날짜, 시간 id, 테마 id, 예약자 id에 유효하지 않은 값이 입력 되었을 때 | ||
- [x] 날짜: null, "", yyyy-MM-dd이 아닌 경우 | ||
- [x] 시간 id: null, 1 이상이 아닌 경우 | ||
- [x] 테마 id: null, 1 이상이 아닌 경우 | ||
- [x] 예약자 id: null, 1 이상이 아닌 경우 | ||
- [x] 특정 시간에 대한 예약이 존재하는데, 그 시간을 삭제하려 할 때 | ||
- [x] 특정 테마에 대한 예약이 존재하는데, 그 테마를 삭제하려 할 때 | ||
- [x] 존재하지 않는 id를 가진 데이터에 접근하려 할 때 | ||
- [x] 지나간 날짜와 시간에 대한 예약을 생성하려 할 때 | ||
- [x] 중복 예약을 생성하려 할 때 | ||
- [x] 중복 예약 시간을 생성하려 할 때 | ||
- [x] 이름이 중복된 테마를 생성하려 할 때 | ||
|
||
### 예약 시간 | ||
- [x] 관리자 시간 관리 페이지 조회 | ||
- [x] 시간 추가 | ||
- [x] 시간 삭제 | ||
- [x] 시간 조회 | ||
|
||
### 테마 | ||
- [x] 관리자 테마 관리 페이지 조회 | ||
- [x] 테마 추가 | ||
- [x] 테마 삭제 | ||
- [x] 테마 조회 | ||
|
||
### 사용자 | ||
- [x] 로그인 페이지 조회 | ||
- [x] 로그인 | ||
- [x] 로그아웃 | ||
- [x] 사용자 정보 조회 | ||
- [x] 사용자 목록 조회 | ||
- [x] 접근 권한 제어 | ||
- [x] 관리자 페이지(/admin/**) 진입은 권한이 있는 사람만 할 수 있도록 제한 | ||
|
||
### 예약 | ||
- [x] 관리자의 예약 추가 | ||
- [x] 관리자 예약 페이지 조회 | ||
- [x] 사용자의 예약 추가 | ||
- [X] 사용자 예약 페이지 조회 | ||
- [x] 테마와 날짜 선택 시 예약 가능 시간 조회 | ||
- [x] 로그인 사용자 정보 활용 | ||
- [x] 예약 추가 | ||
- [x] 인기 테마 조회 기능 | ||
- [x] 인기 테마 페이지 조회 | ||
- [x] 최근 일주일 기준, 해당 기간 내 예약이 많은 테마 10개 확인 | ||
- [x] 예약 목록 검색 | ||
- [x] 관리자가 조건에 따라 예약 검색 | ||
- [x] 예약자별, 테마별, 날짜별 검색 조건 | ||
- [x] 사용자의 예약 목록 조회 | ||
- [x] 로그인 사용자 정보 활용 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package roomescape.controller; | ||
|
||
import jakarta.validation.Valid; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import roomescape.controller.request.AdminReservationRequest; | ||
import roomescape.controller.response.ReservationResponse; | ||
import roomescape.model.Reservation; | ||
import roomescape.service.ReservationService; | ||
import roomescape.service.dto.ReservationDto; | ||
|
||
import java.net.URI; | ||
|
||
@RestController | ||
@RequestMapping("/admin") | ||
public class AdminController { | ||
|
||
private final ReservationService reservationService; | ||
|
||
public AdminController(ReservationService reservationService) { | ||
this.reservationService = reservationService; | ||
} | ||
|
||
@PostMapping("/reservations") | ||
public ResponseEntity<ReservationResponse> addReservation(@Valid @RequestBody AdminReservationRequest request) { | ||
ReservationDto reservationDto = ReservationDto.from(request); | ||
Reservation reservation = reservationService.saveReservation(reservationDto); | ||
ReservationResponse response = ReservationResponse.from(reservation); | ||
return ResponseEntity | ||
.created(URI.create("/admin/reservations/" + response.getId())) | ||
.body(response); | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
src/main/java/roomescape/controller/AdminPageController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package roomescape.controller; | ||
|
||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
|
||
@Controller | ||
@RequestMapping("/admin") | ||
public class AdminPageController { | ||
|
||
@GetMapping | ||
public String getHome() { | ||
return "admin/index"; | ||
} | ||
|
||
@GetMapping("/reservation") | ||
public String getReservation() { | ||
return "admin/reservation-new"; | ||
} | ||
|
||
@GetMapping("/time") | ||
public String getReservationTime() { | ||
return "admin/time"; | ||
} | ||
|
||
@GetMapping("/theme") | ||
public String getTheme() { | ||
return "admin/theme"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package roomescape.controller; | ||
|
||
import jakarta.servlet.http.Cookie; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.validation.Valid; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.ResponseCookie; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import roomescape.controller.request.LoginRequest; | ||
import roomescape.controller.response.LoginResponse; | ||
import roomescape.exception.AuthorizationException; | ||
import roomescape.service.AuthService; | ||
import roomescape.service.dto.AuthDto; | ||
import roomescape.service.dto.MemberInfo; | ||
|
||
import java.util.Arrays; | ||
import java.util.Optional; | ||
|
||
@Controller | ||
public class AuthController { | ||
|
||
private static final String AUTH_COOKIE_KEY = "token"; | ||
|
||
private final AuthService authService; | ||
|
||
public AuthController(AuthService authService) { | ||
this.authService = authService; | ||
} | ||
|
||
@PostMapping("/login") | ||
public ResponseEntity<Void> login(@Valid @RequestBody LoginRequest loginRequest) { | ||
AuthDto authDto = AuthDto.from(loginRequest); | ||
String token = authService.createToken(authDto); | ||
ResponseCookie cookie = createCookie(token, 3600); | ||
return ResponseEntity.ok() | ||
.header(HttpHeaders.SET_COOKIE, cookie.toString()) | ||
.build(); | ||
} | ||
|
||
@GetMapping("/login/check") | ||
public ResponseEntity<LoginResponse> checkLogin(HttpServletRequest request) { | ||
Cookie token = findCookieByKey(request.getCookies(), AUTH_COOKIE_KEY).orElseThrow(AuthorizationException::new); | ||
MemberInfo loginMember = authService.checkToken(token.getValue()); | ||
LoginResponse response = LoginResponse.from(loginMember); | ||
return ResponseEntity.ok(response); | ||
} | ||
|
||
@PostMapping("/logout") | ||
public ResponseEntity<Void> logout() { | ||
ResponseCookie cookie = createCookie(null, 0); | ||
return ResponseEntity.ok() | ||
.header(HttpHeaders.SET_COOKIE, cookie.toString()) | ||
.build(); | ||
} | ||
|
||
private ResponseCookie createCookie(String token, long maxAge) { | ||
return ResponseCookie | ||
.from(AUTH_COOKIE_KEY, token) | ||
.maxAge(maxAge) | ||
.httpOnly(true) | ||
.path("/") | ||
.build(); | ||
} | ||
|
||
private Optional<Cookie> findCookieByKey(Cookie[] cookies, String key) { | ||
return Arrays.stream(cookies) | ||
.filter(cookie -> cookie.getName().equals(key)) | ||
.findFirst(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package roomescape.controller; | ||
|
||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import roomescape.controller.response.MemberResponse; | ||
import roomescape.model.member.Member; | ||
import roomescape.service.MemberService; | ||
|
||
import java.util.List; | ||
|
||
@RestController | ||
@RequestMapping("/members") | ||
public class MemberController { | ||
|
||
private final MemberService memberService; | ||
|
||
public MemberController(MemberService memberService) { | ||
this.memberService = memberService; | ||
} | ||
|
||
@GetMapping | ||
public ResponseEntity<List<MemberResponse>> getMembers() { | ||
List<Member> members = memberService.findAllMembers(); | ||
List<MemberResponse> response = members.stream() | ||
.map(MemberResponse::from) | ||
.toList(); | ||
return ResponseEntity.ok(response); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package roomescape.controller; | ||
|
||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
|
||
@Controller | ||
public class PageController { | ||
|
||
@GetMapping | ||
public String getHome() { | ||
return "index"; | ||
} | ||
|
||
@GetMapping("/reservation") | ||
public String getReservation() { | ||
return "reservation"; | ||
} | ||
|
||
@GetMapping("/login") | ||
public String getLoginPage() { | ||
return "login"; | ||
} | ||
|
||
@GetMapping("/reservation-mine") | ||
public String getMyReservationPage() { | ||
return "reservation-mine"; | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
src/main/java/roomescape/controller/ReservationController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package roomescape.controller; | ||
|
||
import jakarta.validation.Valid; | ||
import jakarta.validation.constraints.Min; | ||
import jakarta.validation.constraints.NotNull; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
import roomescape.controller.request.ReservationRequest; | ||
import roomescape.controller.response.MemberReservationResponse; | ||
import roomescape.controller.response.ReservationResponse; | ||
import roomescape.controller.response.ReservationTimeInfoResponse; | ||
import roomescape.model.Reservation; | ||
import roomescape.model.member.LoginMember; | ||
import roomescape.service.ReservationService; | ||
import roomescape.service.dto.ReservationDto; | ||
import roomescape.service.dto.ReservationTimeInfoDto; | ||
|
||
import java.net.URI; | ||
import java.time.LocalDate; | ||
import java.util.List; | ||
|
||
@RestController | ||
@RequestMapping("/reservations") | ||
public class ReservationController { | ||
|
||
private final ReservationService reservationService; | ||
|
||
public ReservationController(ReservationService reservationService) { | ||
this.reservationService = reservationService; | ||
} | ||
|
||
@GetMapping | ||
public ResponseEntity<List<ReservationResponse>> getReservations() { | ||
List<Reservation> reservations = reservationService.findAllReservations(); | ||
List<ReservationResponse> response = reservations.stream() | ||
.map(ReservationResponse::from) | ||
.toList(); | ||
return ResponseEntity.ok(response); | ||
} | ||
|
||
@PostMapping | ||
public ResponseEntity<ReservationResponse> addReservation(@Valid @RequestBody ReservationRequest request, LoginMember member) { | ||
ReservationDto reservationDto = ReservationDto.of(request, member); | ||
Reservation reservation = reservationService.saveReservation(reservationDto); | ||
ReservationResponse response = ReservationResponse.from(reservation); | ||
return ResponseEntity | ||
.created(URI.create("/reservations/" + response.getId())) | ||
.body(response); | ||
} | ||
|
||
@DeleteMapping("/{id}") | ||
public ResponseEntity<Void> deleteReservation(@NotNull @Min(1) @PathVariable("id") Long id) { | ||
reservationService.deleteReservation(id); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
|
||
@GetMapping(value = "/times", params = {"date", "themeId"}) | ||
public ResponseEntity<List<ReservationTimeInfoResponse>> showReservationTimesInformation(@NotNull LocalDate date, | ||
@NotNull @Min(1) Long themeId) { | ||
ReservationTimeInfoDto timesInfo = reservationService.findReservationTimesInformation(date, themeId); | ||
List<ReservationTimeInfoResponse> response = ReservationTimeInfoResponse.from(timesInfo); | ||
return ResponseEntity.ok(response); | ||
} | ||
|
||
@GetMapping(value = "/filter", params = {"memberId", "themeId", "from", "to"}) | ||
public ResponseEntity<List<ReservationResponse>> searchReservations(@NotNull @Min(1) Long memberId, | ||
@NotNull @Min(1) Long themeId, | ||
@NotNull LocalDate from, | ||
@NotNull LocalDate to) { | ||
List<Reservation> responses = reservationService.findReservationsByConditions(memberId, themeId, from, to); | ||
List<ReservationResponse> response = responses.stream() | ||
.map(ReservationResponse::from) | ||
.toList(); | ||
return ResponseEntity.ok(response); | ||
} | ||
|
||
@GetMapping("/mine") | ||
public ResponseEntity<List<MemberReservationResponse>> getReservationsOfMember(LoginMember member) { | ||
List<Reservation> reservations = reservationService.findReservationsByMember(member); | ||
List<MemberReservationResponse> response = reservations.stream() | ||
.map((MemberReservationResponse::new)) | ||
.toList(); | ||
return ResponseEntity.ok(response); | ||
} | ||
} |
Oops, something went wrong.