-
Notifications
You must be signed in to change notification settings - Fork 161
[1 - 2단계 방탈출 예약 대기] 조이썬(이영수) 미션 제출합니다. #65
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
Merged
Merged
Changes from all commits
Commits
Show all changes
54 commits
Select commit
Hold shift + click to select a range
bdd1386
feat : migration code
youngsu5582 4519cc5
feat(ReservationTimeRepository) : JDBC->JPA 변환 구현
youngsu5582 744ae68
feat(ThemeRepository) : JDBC->JPA 변환 구현
youngsu5582 7b3d930
feat(MemberRepository) : JDBC->JPA 변환 구현
youngsu5582 ad235f6
feat(ReservationRepository) : JDBC->JPA 변환 구현
youngsu5582 39059a8
feat(ThemeRepository) : 인기 테마 가져오는 기능 JPA 통해 구현
youngsu5582 5ef8412
feat(ReservationTimeRepository) : 예약 가능한 시간 받는 기능 구현
youngsu5582 27f7154
feat(ReservationTimeRepository) : 예약 가능한 시간 받는 기능 구현
youngsu5582 338f91e
feat(MemberService) : Dao -> Repository 교체
youngsu5582 708f8b7
feat(ThemeService) : Dao -> Repository 교체
youngsu5582 f21b4f0
feat(ReservationTime) : Dao -> Repository 교체
youngsu5582 a8de7d6
feat(Reservation) : Dao -> Repository 교체
youngsu5582 07f981d
feat(AvailableReservationTime) : record 삭제,이름 변경
youngsu5582 224b9bb
refactor(dao,mapper) : JPA 변환으로 삭제
youngsu5582 b5df1ee
feat(Member) : 저장시, Enum 문자열 값으로 저장되게 변경
youngsu5582 1347476
test : 불필요한 테스트 코드 삭제
youngsu5582 515731f
docs : 기능 요구사항 초안 정리
youngsu5582 80abf8f
feat(Reservation) : 예약 상태 추가
youngsu5582 7ec5d4a
feat(ReservationService): 자신이 예약한 예약들 가져오는 기능 구현
youngsu5582 eb25e66
feat(ReservationController): 자신이 예약한 예약들 응답 기능 구현
youngsu5582 09c0665
feat(MemberPageController): 내 예약 페이지 응답 기능 구현
youngsu5582 460d288
fix(ReservationApiController): API 응답 dto 수정
youngsu5582 f0a0e0f
refactor: Inserter 패키지 이동
youngsu5582 ab306cb
test: 내 예약 페이지 응답 기능 테스트 구현
youngsu5582 e3cebb1
feat : 초기 데이터 설정,스키마 파일 삭제
youngsu5582 3eb91ac
test : DB 초기화 로직 변경
youngsu5582 6fc0406
feat(Theme) : ID 생성 전략 추가
youngsu5582 4e6b328
fix : test 시에도 지연 생성 설정 추가
youngsu5582 df19cdf
refactor : dao->repository 로 패키지명 변경
youngsu5582 e182a1c
refactor(all) : 코드 자동 정렬
youngsu5582 e31488a
refactor(ReservationApiController) : RequestMapping 경로 추가로 다시 경로 응집성 …
youngsu5582 903776d
refactor(LoginApiController) : ResponseCookie 로 변경
youngsu5582 68862dd
refactor(ThemeApiController) : RestController 로 변경
youngsu5582 54c32b4
refactor(All) : 사용하지 않는 불필요한 코드들 제거
youngsu5582 68c7e5e
feat(Thumbnail) : 확장자 검사 기능 제거
youngsu5582 281bf69
test : SpringBootTest 로 변경
youngsu5582 b43aac7
feat(Interceptor) : 인터셉터 순서 지정해 Login->Admin 순으로 동작하게 변경
youngsu5582 0737bee
test(Acceptance) : 인수테스트 초기 설정
youngsu5582 40da556
refactor(AuthController) : 컨트롤러 명 변경, 기능 이동
youngsu5582 fe2a339
feat(MemberService) : 로그인 중 발생하는 예외 변경
youngsu5582 9835145
feat(ReservationService) : 삭제한 값이 없을때 예외 발생 기능 구현
youngsu5582 f029bf1
test(AuthAcceptanceTest) : 로그인 확인 기능에 대한 인수 테스트 구현
youngsu5582 4dc87d9
feat(Member,MemberRepository) : 이메일 문자열로 검색하게 변경, 칼럼명 지정
youngsu5582 0152657
feat(Reservation) : 불필요한 생성자내 Id 매개변수 제거
youngsu5582 e7d59c6
test : 인수 테스트 전환으로 인해 컨트롤러 테스트 제거
youngsu5582 0363cf1
refactor(Member) : 불필요한 정적 팩토리 제거
youngsu5582 352cd21
refactor : 빈 생성자 접근 제한자 변경
youngsu5582 9467dad
feat(Theme,ReservationTime,Member) : 불필요한 생성자내 Id 매개변수 제거
youngsu5582 83797ec
feat(TokenContextRequest) : 불필요한 ScopeBean 삭제
youngsu5582 c92b8ba
feat : unique 제약 조건 추가
youngsu5582 50a3078
test(Interceptor) : controller->config 패키지로 이동
youngsu5582 17ab3e9
feat(ReservationTimeService) : 예약가능 시간 조회 기능 로직 변경
youngsu5582 d053f77
refactor(Reservation) : 예약 날짜 검색 메소드명 자연스럽게 변경
youngsu5582 a8069e6
fix(Reservation) : 누락된 예약 날짜 검색 메소드명 변경 내역 수정
youngsu5582 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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,6 @@ | ||
| ## 방탈출 예약 대기 | ||
|
|
||
| ### 기능 요구 사항 | ||
|
|
||
| - [x] 내 예약 목록을 조회하는 API를 구현한다. | ||
|
|
This file contains hidden or 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 hidden or 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
22 changes: 22 additions & 0 deletions
22
src/main/java/roomescape/config/CheckAdminInterceptor.java
This file contains hidden or 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,22 @@ | ||
| package roomescape.config; | ||
|
|
||
|
|
||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import jakarta.servlet.http.HttpServletResponse; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.web.servlet.HandlerInterceptor; | ||
| import roomescape.exception.ForbiddenException; | ||
| import roomescape.service.dto.output.TokenLoginOutput; | ||
|
|
||
| @Component | ||
| public class CheckAdminInterceptor implements HandlerInterceptor { | ||
| @Override | ||
| public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) { | ||
| final TokenLoginOutput output = (TokenLoginOutput) request.getAttribute("member"); | ||
| if (output != null && output.isAdmin()) { | ||
| return true; | ||
| } | ||
| throw new ForbiddenException(request.getRequestURI()); | ||
| } | ||
| } | ||
|
|
||
39 changes: 39 additions & 0 deletions
39
src/main/java/roomescape/config/CheckLoginInterceptor.java
This file contains hidden or 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,39 @@ | ||
| package roomescape.config; | ||
|
|
||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import jakarta.servlet.http.HttpServletResponse; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.web.servlet.HandlerInterceptor; | ||
| import roomescape.service.MemberService; | ||
| import roomescape.service.dto.output.TokenLoginOutput; | ||
| import roomescape.util.TokenProvider; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Component | ||
| public class CheckLoginInterceptor implements HandlerInterceptor { | ||
| private static final List<String> CHECK_LIST = initializeCheckList(); | ||
| private final MemberService memberService; | ||
| private final TokenProvider tokenProvider; | ||
|
|
||
| private static List<String> initializeCheckList() { | ||
| return List.of("/reservations"); | ||
| } | ||
|
|
||
| public CheckLoginInterceptor(final MemberService memberService, final TokenProvider tokenProvider) { | ||
| this.memberService = memberService; | ||
| this.tokenProvider = tokenProvider; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) { | ||
| if (request.getMethod() | ||
| .equals("GET") && CHECK_LIST.contains(request.getRequestURI())) { | ||
| return true; | ||
| } | ||
| final String token = tokenProvider.parseToken(request); | ||
| final TokenLoginOutput output = memberService.loginToken(token); | ||
| request.setAttribute("member", output); | ||
| return true; | ||
| } | ||
| } |
This file contains hidden or 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,40 @@ | ||
| package roomescape.config; | ||
|
|
||
| import org.springframework.context.annotation.Configuration; | ||
| import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||
| import org.springframework.web.servlet.config.annotation.InterceptorRegistry; | ||
| import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | ||
| import roomescape.controller.LoginMemberArgumentResolver; | ||
| import roomescape.service.MemberService; | ||
| import roomescape.util.TokenProvider; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| @Configuration | ||
| public class WebMvcConfiguration implements WebMvcConfigurer { | ||
| private final MemberService memberService; | ||
| private final TokenProvider tokenProvider; | ||
|
|
||
| public WebMvcConfiguration(final MemberService memberService, final TokenProvider tokenProvider) { | ||
| this.memberService = memberService; | ||
| this.tokenProvider = tokenProvider; | ||
| } | ||
|
|
||
|
|
||
| @Override | ||
| public void addInterceptors(final InterceptorRegistry registry) { | ||
| registry.addInterceptor(new CheckLoginInterceptor(memberService, tokenProvider)) | ||
| .addPathPatterns("/login/check") | ||
| .addPathPatterns("/reservations/**") | ||
| .addPathPatterns("/admin/**") | ||
| .order(1); | ||
| registry.addInterceptor(new CheckAdminInterceptor()) | ||
| .addPathPatterns("/admin/**") | ||
| .order(2); | ||
| } | ||
|
|
||
| @Override | ||
| public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> resolvers) { | ||
| resolvers.add(new LoginMemberArgumentResolver()); | ||
| } | ||
| } |
32 changes: 32 additions & 0 deletions
32
src/main/java/roomescape/controller/LoginMemberArgumentResolver.java
This file contains hidden or 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,32 @@ | ||
| package roomescape.controller; | ||
|
|
||
| import jakarta.servlet.http.HttpServletRequest; | ||
| import org.springframework.core.MethodParameter; | ||
| import org.springframework.stereotype.Component; | ||
| import org.springframework.web.bind.support.WebDataBinderFactory; | ||
| import org.springframework.web.context.request.NativeWebRequest; | ||
| import org.springframework.web.method.support.HandlerMethodArgumentResolver; | ||
| import org.springframework.web.method.support.ModelAndViewContainer; | ||
| import roomescape.controller.api.dto.request.LoginMemberRequest; | ||
| import roomescape.exception.UnauthorizedException; | ||
| import roomescape.service.dto.output.TokenLoginOutput; | ||
|
|
||
|
|
||
| @Component | ||
| public class LoginMemberArgumentResolver implements HandlerMethodArgumentResolver { | ||
| @Override | ||
| public boolean supportsParameter(final MethodParameter parameter) { | ||
| return parameter.getParameterType() | ||
| .equals(LoginMemberRequest.class); | ||
| } | ||
|
|
||
| @Override | ||
| public LoginMemberRequest resolveArgument(final MethodParameter parameter, final ModelAndViewContainer mavContainer, final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) throws Exception { | ||
| final HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); | ||
| final TokenLoginOutput output = (TokenLoginOutput) request.getAttribute("member"); | ||
| if (output == null) { | ||
| throw new UnauthorizedException(); | ||
| } | ||
| return new LoginMemberRequest(output.id(), output.email(), output.password(), output.name()); | ||
| } | ||
| } |
31 changes: 31 additions & 0 deletions
31
src/main/java/roomescape/controller/api/AdminApiController.java
This file contains hidden or 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.api; | ||
|
|
||
| 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.api.dto.request.AdminReservationRequest; | ||
| import roomescape.controller.api.dto.response.ReservationResponse; | ||
| import roomescape.service.ReservationService; | ||
| import roomescape.service.dto.output.ReservationOutput; | ||
|
|
||
| import java.net.URI; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/admin") | ||
| public class AdminApiController { | ||
|
|
||
| ReservationService reservationService; | ||
|
|
||
| public AdminApiController(final ReservationService reservationService) { | ||
| this.reservationService = reservationService; | ||
| } | ||
|
|
||
| @PostMapping("/reservations") | ||
| public ResponseEntity<ReservationResponse> createReservation(@RequestBody final AdminReservationRequest request) { | ||
| final ReservationOutput output = reservationService.createReservation(request.toInput()); | ||
| return ResponseEntity.created(URI.create("/reservations/" + output.id())) | ||
| .body(ReservationResponse.toResponse(output)); | ||
| } | ||
| } |
57 changes: 57 additions & 0 deletions
57
src/main/java/roomescape/controller/api/AuthApiController.java
This file contains hidden or 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,57 @@ | ||
| package roomescape.controller.api; | ||
|
|
||
| import jakarta.servlet.http.HttpServletResponse; | ||
| import org.springframework.http.HttpHeaders; | ||
| import org.springframework.http.ResponseCookie; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
| import roomescape.controller.api.dto.request.LoginMemberRequest; | ||
| import roomescape.controller.api.dto.request.MemberCreateRequest; | ||
| import roomescape.controller.api.dto.request.MemberLoginRequest; | ||
| import roomescape.controller.api.dto.response.TokenLoginResponse; | ||
| import roomescape.service.MemberService; | ||
| import roomescape.service.dto.output.MemberCreateOutput; | ||
| import roomescape.service.dto.output.MemberLoginOutput; | ||
|
|
||
| import java.net.URI; | ||
|
|
||
| @RestController | ||
| public class AuthApiController { | ||
| private final MemberService memberService; | ||
|
|
||
| public AuthApiController(final MemberService memberService) { | ||
| this.memberService = memberService; | ||
| } | ||
|
|
||
| @PostMapping("/signup") | ||
| public ResponseEntity<Void> createMember(@RequestBody final MemberCreateRequest request) { | ||
| final MemberCreateOutput output = memberService.createMember(request.toInput()); | ||
| return ResponseEntity.created(URI.create("/reservations/" + output.id())) | ||
| .build(); | ||
| } | ||
|
|
||
| @PostMapping("/login") | ||
| public ResponseEntity<Void> login(@RequestBody final MemberLoginRequest memberLoginRequest, final HttpServletResponse response) { | ||
| final MemberLoginOutput output = memberService.loginMember(memberLoginRequest.toInput()); | ||
| final ResponseCookie cookie = initializeCookie(output.token()); | ||
|
|
||
| return ResponseEntity.ok() | ||
| .header(HttpHeaders.SET_COOKIE, cookie.toString()) | ||
| .build(); | ||
| } | ||
|
|
||
| private ResponseCookie initializeCookie(final String token) { | ||
| return ResponseCookie.from("token", token) | ||
| .httpOnly(true) | ||
| .path("/") | ||
| .build(); | ||
| } | ||
|
|
||
| @GetMapping("/login/check") | ||
| public ResponseEntity<TokenLoginResponse> checkLogin(final LoginMemberRequest request) { | ||
| return ResponseEntity.ok(new TokenLoginResponse(request.name())); | ||
| } | ||
| } |
24 changes: 24 additions & 0 deletions
24
src/main/java/roomescape/controller/api/MemberApiController.java
This file contains hidden or 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,24 @@ | ||
| package roomescape.controller.api; | ||
|
|
||
| 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.api.dto.response.MembersResponse; | ||
| import roomescape.service.MemberService; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/members") | ||
| public class MemberApiController { | ||
| private final MemberService memberService; | ||
|
|
||
| public MemberApiController(final MemberService memberService) { | ||
| this.memberService = memberService; | ||
| } | ||
|
|
||
| @GetMapping | ||
| public ResponseEntity<MembersResponse> getAllMembers() { | ||
| final var output = memberService.getAllMembers(); | ||
| return ResponseEntity.ok(MembersResponse.toResponse(output)); | ||
| } | ||
| } |
64 changes: 64 additions & 0 deletions
64
src/main/java/roomescape/controller/api/ReservationApiController.java
This file contains hidden or 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,64 @@ | ||
| package roomescape.controller.api; | ||
|
|
||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.*; | ||
| import roomescape.controller.api.dto.request.LoginMemberRequest; | ||
| import roomescape.controller.api.dto.request.ReservationRequest; | ||
| import roomescape.controller.api.dto.response.MemberReservationsResponse; | ||
| import roomescape.controller.api.dto.response.ReservationResponse; | ||
| import roomescape.controller.api.dto.response.ReservationsResponse; | ||
| import roomescape.service.ReservationService; | ||
| import roomescape.service.dto.input.ReservationSearchInput; | ||
| import roomescape.service.dto.output.ReservationOutput; | ||
|
|
||
| import java.net.URI; | ||
| import java.time.LocalDate; | ||
| import java.util.List; | ||
|
|
||
| @RestController | ||
| @RequestMapping("/reservations") | ||
| public class ReservationApiController { | ||
|
|
||
| private final ReservationService reservationService; | ||
|
|
||
| public ReservationApiController(final ReservationService reservationService) { | ||
| this.reservationService = reservationService; | ||
| } | ||
|
|
||
| @PostMapping | ||
| public ResponseEntity<ReservationResponse> createReservation(@RequestBody final ReservationRequest reservationRequest, | ||
| final LoginMemberRequest loginMemberRequest) { | ||
| final ReservationOutput output = reservationService.createReservation(reservationRequest.toInput(loginMemberRequest.id())); | ||
| return ResponseEntity.created(URI.create("/reservations/" + output.id())) | ||
| .body(ReservationResponse.toResponse(output)); | ||
| } | ||
|
|
||
| @GetMapping | ||
| public ResponseEntity<ReservationsResponse> getAllReservations() { | ||
| final List<ReservationOutput> outputs = reservationService.getAllReservations(); | ||
| return ResponseEntity.ok(ReservationsResponse.toResponse(outputs)); | ||
| } | ||
|
|
||
| @GetMapping("/search") | ||
| public ResponseEntity<ReservationsResponse> searchReservation( | ||
| @RequestParam final long themeId, | ||
| @RequestParam final long memberId, | ||
| @RequestParam final LocalDate fromDate, | ||
| @RequestParam final LocalDate toDate) { | ||
| final List<ReservationOutput> outputs = reservationService.searchReservation(new ReservationSearchInput(themeId, memberId, fromDate, toDate)); | ||
| return ResponseEntity.ok(ReservationsResponse.toResponse(outputs)); | ||
| } | ||
|
|
||
| @GetMapping("/mine") | ||
| public ResponseEntity<MemberReservationsResponse> getMyReservations(final LoginMemberRequest loginMemberRequest) { | ||
| final List<ReservationOutput> outputs = reservationService.getAllMyReservations(loginMemberRequest.id()); | ||
| return ResponseEntity.ok(MemberReservationsResponse.toResponse(outputs)); | ||
| } | ||
|
|
||
| @DeleteMapping("/{id}") | ||
| public ResponseEntity<Void> deleteReservation(@PathVariable final long id) { | ||
| reservationService.deleteReservation(id); | ||
| return ResponseEntity.noContent() | ||
| .build(); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.