Skip to content
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

[1단계 방탈출 결제 / 배포] 알파카(최휘용) 미션 제출합니다. #36

Merged
merged 15 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
443 changes: 443 additions & 0 deletions README.md

Large diffs are not rendered by default.

10 changes: 3 additions & 7 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,12 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'

implementation 'io.jsonwebtoken:jjwt-api:0.11.2'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.2'
implementation 'io.jsonwebtoken:jjwt-gson:0.11.2'

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// JWT 라이브러리. https://github.com/jwtk/jjwt
implementation 'io.jsonwebtoken:jjwt:0.12.5'
runtimeOnly 'com.h2database:h2'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.1'
}

test {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/roomescape/RoomescapeApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

@SpringBootApplication
public class RoomescapeApplication {

public static void main(String[] args) {
SpringApplication.run(RoomescapeApplication.class, args);
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/roomescape/annotation/Auth.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package roomescape.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Auth {
}
23 changes: 23 additions & 0 deletions src/main/java/roomescape/config/TimeFormatterConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package roomescape.config;

import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import java.time.format.DateTimeFormatter;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TimeFormatterConfig {
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");

@Bean
public Jackson2ObjectMapperBuilderCustomizer localTimeSerializerCustomizer() {
return builder -> builder.serializers(new LocalTimeSerializer(TIME_FORMATTER),
new LocalDateSerializer(DATE_FORMATTER))
.deserializers(new LocalTimeDeserializer(TIME_FORMATTER), new LocalDateDeserializer(DATE_FORMATTER));
}
}
38 changes: 38 additions & 0 deletions src/main/java/roomescape/config/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package roomescape.config;

import java.util.List;
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.infra.AdminCheckInterceptor;
import roomescape.infra.AuthArgumentResolver;
import roomescape.infra.LoginCheckInterceptor;

@Configuration
public class WebConfig implements WebMvcConfigurer {
private final AuthArgumentResolver authArgumentResolver;
private final AdminCheckInterceptor adminCheckInterceptor;
private final LoginCheckInterceptor loginCheckInterceptor;

public WebConfig(AuthArgumentResolver authArgumentResolver, AdminCheckInterceptor adminCheckInterceptor,
LoginCheckInterceptor loginCheckInterceptor) {
this.authArgumentResolver = authArgumentResolver;
this.adminCheckInterceptor = adminCheckInterceptor;
this.loginCheckInterceptor = loginCheckInterceptor;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(adminCheckInterceptor)
.addPathPatterns("/admin/**");
registry.addInterceptor(loginCheckInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/login/**", "/", "/themes/ranking", "/**/*.html", "/**/*.js", "/**/*.css");
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(authArgumentResolver);
}
}
67 changes: 67 additions & 0 deletions src/main/java/roomescape/controller/AdminController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package roomescape.controller;

import java.net.URI;
import java.time.LocalDate;
import java.util.List;
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 org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import roomescape.dto.ReservationRequest;
import roomescape.dto.ReservationResponse;
import roomescape.service.ReservationService;

@Controller
@RequestMapping("/admin")
public class AdminController {
private final ReservationService reservationService;

public AdminController(ReservationService reservationService) {
this.reservationService = reservationService;
}

@GetMapping
public String mainPage() {
return "admin/index";
}

@GetMapping("/reservation")
public String reservationPage() {
return "admin/reservation-new";
}

@PostMapping("/reservations")
public ResponseEntity<ReservationResponse> saveReservation(@RequestBody ReservationRequest reservationRequest) {
ReservationResponse saved = reservationService.save(reservationRequest);
return ResponseEntity.created(URI.create("/reservations/" + saved.id()))
.body(saved);
}

@GetMapping("/reservations")
@ResponseBody
public List<ReservationResponse> search(@RequestParam long memberId,
@RequestParam long themeId,
@RequestParam LocalDate start,
@RequestParam LocalDate end) {
return reservationService.findByMemberAndThemeBetweenDates(memberId, themeId, start, end);
}

@GetMapping("/time")
public String reservationTimePage() {
return "admin/time";
}

@GetMapping("/theme")
public String themePage() {
return "admin/theme";
}

@GetMapping("/waiting")
public String waitingManagePage() {
return "admin/waiting";
}
}
53 changes: 53 additions & 0 deletions src/main/java/roomescape/controller/MemberController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package roomescape.controller;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
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.annotation.Auth;
import roomescape.dto.LoginRequest;
import roomescape.dto.MemberInfo;
import roomescape.service.MemberService;
import roomescape.service.TokenService;

@RestController
public class MemberController {
private final MemberService memberService;
private final TokenService tokenService;

public MemberController(MemberService memberService, TokenService tokenService) {
this.memberService = memberService;
this.tokenService = tokenService;
}

@PostMapping("/login")
public ResponseEntity<Void> login(@RequestBody LoginRequest loginRequest) {
long memberId = memberService.login(loginRequest);
LocalDateTime now = LocalDateTime.now();
Duration tokenLifeTime = Duration.between(now, now.plusHours(1));
String token = tokenService.createToken(memberId, now, tokenLifeTime);
ResponseCookie cookie = ResponseCookie.from("token", token)
.httpOnly(true)
.maxAge(tokenLifeTime)
.build();
return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, cookie.toString())
.build();
}

@GetMapping("/login/check")
public MemberInfo myInfo(@Auth long memberId) {
return memberService.findByMemberId(memberId);
}

@GetMapping("/members")
public List<MemberInfo> allMembers() {
return memberService.findAll();
}
}
67 changes: 67 additions & 0 deletions src/main/java/roomescape/controller/ReservationController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package roomescape.controller;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.annotation.Auth;
import roomescape.dto.LoginMemberReservationResponse;
import roomescape.dto.ReservationRequest;
import roomescape.dto.ReservationResponse;
import roomescape.service.PaymentService;
import roomescape.service.ReservationService;
import roomescape.service.ReservationWaitingService;

@RestController
@RequestMapping("/reservations")
public class ReservationController {
private final ReservationService reservationService;
private final ReservationWaitingService waitingService;
private final PaymentService paymentService;

public ReservationController(ReservationService reservationService, ReservationWaitingService waitingService,
PaymentService paymentService) {
this.reservationService = reservationService;
this.waitingService = waitingService;
this.paymentService = paymentService;
}

@PostMapping
public ResponseEntity<ReservationResponse> saveReservation(@Auth long memberId,
@RequestBody ReservationRequest reservationRequest) {
reservationRequest = new ReservationRequest(reservationRequest.date(), memberId, reservationRequest.timeId(),
reservationRequest.themeId(), reservationRequest.approveRequest());
paymentService.approve(reservationRequest.approveRequest(), memberId);
ReservationResponse saved = reservationService.save(reservationRequest);
return ResponseEntity.created(URI.create("/reservations/" + saved.id()))
.body(saved);
}

@GetMapping
public List<ReservationResponse> findAllReservations() {
return reservationService.findAll();
}

@GetMapping("/mine")
public List<LoginMemberReservationResponse> findLoginMemberReservations(@Auth long memberId) {
List<LoginMemberReservationResponse> reservations = reservationService.findByMemberId(memberId);
List<LoginMemberReservationResponse> waitings = waitingService.findByMemberId(memberId);

List<LoginMemberReservationResponse> response = new ArrayList<>(reservations);
response.addAll(waitings);
return response;
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@Auth long memberId, @PathVariable("id") long reservationId) {
reservationService.cancel(memberId, reservationId);
return ResponseEntity.noContent().build();
}
}
53 changes: 53 additions & 0 deletions src/main/java/roomescape/controller/ReservationTimeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package roomescape.controller;

import java.net.URI;
import java.time.LocalDate;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import roomescape.dto.AvailableTimeResponse;
import roomescape.dto.ReservationTimeRequest;
import roomescape.dto.ReservationTimeResponse;
import roomescape.service.AvailableTimeService;
import roomescape.service.ReservationTimeService;

@RestController
public class ReservationTimeController {
private final ReservationTimeService reservationTimeService;
private final AvailableTimeService availableTimeService;

public ReservationTimeController(ReservationTimeService reservationTimeService,
AvailableTimeService availableTimeService) {
this.reservationTimeService = reservationTimeService;
this.availableTimeService = availableTimeService;
}

@PostMapping("/admin/times")
public ResponseEntity<ReservationTimeResponse> save(@RequestBody ReservationTimeRequest reservationTimeRequest) {
ReservationTimeResponse saved = reservationTimeService.save(reservationTimeRequest);
return ResponseEntity.created(URI.create("/times/" + saved.id()))
.body(saved);
}

@GetMapping("/times")
public List<ReservationTimeResponse> findAll() {
return reservationTimeService.findAll();
}

@GetMapping(value = "/times", params = {"date", "themeId"})
public List<AvailableTimeResponse> findByThemeAndDate(@RequestParam LocalDate date, @RequestParam long themeId) {
return availableTimeService.findByThemeAndDate(date, themeId);
}

@DeleteMapping("/admin/times/{id}")
public ResponseEntity<Void> delete(@PathVariable long id) {
reservationTimeService.delete(id);
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package roomescape.controller;

import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import roomescape.annotation.Auth;
import roomescape.dto.ReservationRequest;
import roomescape.dto.ReservationWaitingResponse;
import roomescape.service.ReservationWaitingService;

@RestController
public class ReservationWaitingController {
private final ReservationWaitingService waitingService;

public ReservationWaitingController(ReservationWaitingService waitingService) {
this.waitingService = waitingService;
}

@PostMapping("/reservations/waiting")
public ReservationWaitingResponse save(@Auth long memberId, @RequestBody ReservationRequest reservationRequest) {
reservationRequest = new ReservationRequest(reservationRequest.date(), memberId, reservationRequest.timeId(),
reservationRequest.themeId(), reservationRequest.approveRequest());
return waitingService.save(reservationRequest);
}

@DeleteMapping("/reservations/waiting/{id}")
public ResponseEntity<Void> delete(@Auth long memberId, @PathVariable("id") long waitingId) {
waitingService.delete(memberId, waitingId);
return ResponseEntity.noContent().build();
}

@GetMapping("/admin/reservations/waiting")
public List<ReservationWaitingResponse> findAll() {
return waitingService.findAll();
}
}
Loading