diff --git a/src/main/java/nextstep/auth/AuthConfig.java b/src/main/java/nextstep/auth/AuthConfig.java index db64b8fb1..e6e8f0cd2 100644 --- a/src/main/java/nextstep/auth/AuthConfig.java +++ b/src/main/java/nextstep/auth/AuthConfig.java @@ -1,14 +1,13 @@ package nextstep.auth; import com.fasterxml.jackson.databind.ObjectMapper; -import nextstep.auth.authentication.Authorizor; +import nextstep.auth.authentication.Authorizer; import nextstep.auth.authentication.SessionAuthenticationInterceptor; import nextstep.auth.authentication.TokenAuthenticationInterceptor; import nextstep.auth.authorization.AuthenticationPrincipalArgumentResolver; import nextstep.auth.authorization.SessionSecurityContextPersistenceInterceptor; import nextstep.auth.authorization.TokenSecurityContextPersistenceInterceptor; import nextstep.auth.token.JwtTokenProvider; -import nextstep.member.application.CustomUserDetailsService; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @@ -20,19 +19,19 @@ public class AuthConfig implements WebMvcConfigurer { private UserDetailsService userDetailsService; private JwtTokenProvider jwtTokenProvider; private ObjectMapper objectMapper; - private Authorizor authorizor; + private Authorizer authorizor; - public AuthConfig(UserDetailsService userDetailsService, JwtTokenProvider jwtTokenProvider) { + public AuthConfig(UserDetailsService userDetailsService, JwtTokenProvider jwtTokenProvider, ObjectMapper objectMapper) { this.userDetailsService = userDetailsService; this.jwtTokenProvider = jwtTokenProvider; - this.objectMapper = new ObjectMapper(); - this.authorizor = new Authorizor(); + this.objectMapper = objectMapper; + this.authorizor = new Authorizer(userDetailsService); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new SessionAuthenticationInterceptor(userDetailsService, authorizor)).addPathPatterns("/login/session"); - registry.addInterceptor(new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper, authorizor)) + registry.addInterceptor(new TokenAuthenticationInterceptor(jwtTokenProvider, objectMapper, authorizor)) .addPathPatterns("/login/token"); registry.addInterceptor(new SessionSecurityContextPersistenceInterceptor()); registry.addInterceptor(new TokenSecurityContextPersistenceInterceptor(jwtTokenProvider)); diff --git a/src/main/java/nextstep/auth/authentication/Authorizer.java b/src/main/java/nextstep/auth/authentication/Authorizer.java new file mode 100644 index 000000000..ea0ac67d0 --- /dev/null +++ b/src/main/java/nextstep/auth/authentication/Authorizer.java @@ -0,0 +1,33 @@ +package nextstep.auth.authentication; + +import nextstep.auth.User; +import nextstep.auth.UserDetailsService; +import nextstep.auth.context.Authentication; +import org.springframework.util.ObjectUtils; + +public class Authorizer { + + private UserDetailsService userDetailsService; + + public Authorizer(UserDetailsService userDetailsService) { + this.userDetailsService = userDetailsService; + } + + public Authentication authenticate(AuthenticationToken authenticationToken) { + final String principal = authenticationToken.getPrincipal(); + final User userDetails = userDetailsService.loadUserByUsername(principal); + checkAuthentication(userDetails, authenticationToken); + + return new Authentication(userDetails); + } + + private void checkAuthentication(User userDetails, AuthenticationToken token) { + if (ObjectUtils.isEmpty(userDetails)) { + throw new AuthenticationException(); + } + + if (!userDetails.checkPassword(token.getCredentials())) { + throw new AuthenticationException(); + } + } +} diff --git a/src/main/java/nextstep/auth/authentication/Authorizor.java b/src/main/java/nextstep/auth/authentication/Authorizor.java deleted file mode 100644 index 018c46d9a..000000000 --- a/src/main/java/nextstep/auth/authentication/Authorizor.java +++ /dev/null @@ -1,17 +0,0 @@ -package nextstep.auth.authentication; - -import nextstep.auth.User; -import org.springframework.util.ObjectUtils; - -public class Authorizor { - - public void checkAuthentication(User userDetails, AuthenticationToken token) { - if (ObjectUtils.isEmpty(userDetails)) { - throw new AuthenticationException(); - } - - if (!userDetails.checkPassword(token.getCredentials())) { - throw new AuthenticationException(); - } - } -} diff --git a/src/main/java/nextstep/auth/authentication/SessionAuthenticationInterceptor.java b/src/main/java/nextstep/auth/authentication/SessionAuthenticationInterceptor.java index 610a16f54..10b1a7704 100644 --- a/src/main/java/nextstep/auth/authentication/SessionAuthenticationInterceptor.java +++ b/src/main/java/nextstep/auth/authentication/SessionAuthenticationInterceptor.java @@ -1,6 +1,5 @@ package nextstep.auth.authentication; -import nextstep.auth.User; import nextstep.auth.UserDetailsService; import nextstep.auth.context.Authentication; import nextstep.auth.context.SecurityContext; @@ -20,17 +19,17 @@ public class SessionAuthenticationInterceptor implements HandlerInterceptor, Aut public static final String PASSWORD_FIELD = "password"; private UserDetailsService userDetailsService; - private Authorizor authorizor; + private Authorizer authorizor; - public SessionAuthenticationInterceptor(UserDetailsService userDetailsService, Authorizor authorizor) { + public SessionAuthenticationInterceptor(UserDetailsService userDetailsService, Authorizer authorizor) { this.userDetailsService = userDetailsService; this.authorizor = authorizor; } @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { AuthenticationToken token = convert(request); - Authentication authentication = authenticate(token); + Authentication authentication = authorizor.authenticate(token); HttpSession httpSession = request.getSession(); httpSession.setAttribute(SPRING_SECURITY_CONTEXT_KEY, new SecurityContext(authentication)); @@ -38,14 +37,6 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons return false; } - public Authentication authenticate(AuthenticationToken token) { - String principal = token.getPrincipal(); - User userDetails = userDetailsService.loadUserByUsername(principal); - authorizor.checkAuthentication(userDetails, token); - - return new Authentication(userDetails); - } - @Override public AuthenticationToken convert(HttpServletRequest request) { Map paramMap = request.getParameterMap(); diff --git a/src/main/java/nextstep/auth/authentication/TokenAuthenticationInterceptor.java b/src/main/java/nextstep/auth/authentication/TokenAuthenticationInterceptor.java index 216cd21ca..e5881c1dd 100644 --- a/src/main/java/nextstep/auth/authentication/TokenAuthenticationInterceptor.java +++ b/src/main/java/nextstep/auth/authentication/TokenAuthenticationInterceptor.java @@ -1,7 +1,6 @@ package nextstep.auth.authentication; import com.fasterxml.jackson.databind.ObjectMapper; -import nextstep.auth.User; import nextstep.auth.UserDetailsService; import nextstep.auth.context.Authentication; import nextstep.auth.token.JwtTokenProvider; @@ -16,16 +15,13 @@ public class TokenAuthenticationInterceptor implements HandlerInterceptor, AuthenticationConverter { - private UserDetailsService userDetailsService; private JwtTokenProvider jwtTokenProvider; private ObjectMapper objectMapper; - private Authorizor authorizor; + private Authorizer authorizor; - public TokenAuthenticationInterceptor(UserDetailsService userDetailsService, - JwtTokenProvider jwtTokenProvider, + public TokenAuthenticationInterceptor(JwtTokenProvider jwtTokenProvider, ObjectMapper objectMapper, - Authorizor authorizor) { - this.userDetailsService = userDetailsService; + Authorizer authorizor) { this.jwtTokenProvider = jwtTokenProvider; this.objectMapper = objectMapper; this.authorizor = authorizor; @@ -34,7 +30,7 @@ public TokenAuthenticationInterceptor(UserDetailsService userDetailsService, @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { AuthenticationToken authenticationToken = convert(request); - Authentication authentication = authenticate(authenticationToken); + Authentication authentication = authorizor.authenticate(authenticationToken); final String payload = objectMapper.writeValueAsString(authentication.getPrincipal()); final String token = jwtTokenProvider.createToken(payload); @@ -49,14 +45,6 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons return false; } - public Authentication authenticate(AuthenticationToken authenticationToken) { - final String principal = authenticationToken.getPrincipal(); - final User userDetails = userDetailsService.loadUserByUsername(principal); - authorizor.checkAuthentication(userDetails, authenticationToken); - - return new Authentication(userDetails); - } - @Override public AuthenticationToken convert(HttpServletRequest request) throws IOException { TokenRequest tokenRequest = objectMapper.readValue(request.getInputStream(), TokenRequest.class); diff --git a/src/main/java/nextstep/auth/authorization/AuthenticationPrincipalArgumentResolver.java b/src/main/java/nextstep/auth/authorization/AuthenticationPrincipalArgumentResolver.java index 7c776cb80..47dc98171 100644 --- a/src/main/java/nextstep/auth/authorization/AuthenticationPrincipalArgumentResolver.java +++ b/src/main/java/nextstep/auth/authorization/AuthenticationPrincipalArgumentResolver.java @@ -1,8 +1,10 @@ package nextstep.auth.authorization; +import nextstep.auth.authentication.AuthenticationException; import nextstep.auth.context.Authentication; import nextstep.auth.context.SecurityContextHolder; import org.springframework.core.MethodParameter; +import org.springframework.util.ObjectUtils; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; @@ -20,6 +22,7 @@ public boolean supportsParameter(MethodParameter parameter) { @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + authenticationValidate(authentication); if (authentication.getPrincipal() instanceof Map) { return extractPrincipal(parameter, authentication); } @@ -27,6 +30,12 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m return authentication.getPrincipal(); } + private void authenticationValidate(Authentication authentication) { + if (ObjectUtils.isEmpty(authentication)) { + throw new AuthenticationException(); + } + } + private Object extractPrincipal(MethodParameter parameter, Authentication authentication) { try { Map principal = (Map) authentication.getPrincipal(); diff --git a/src/main/java/nextstep/member/application/MemberService.java b/src/main/java/nextstep/member/application/MemberService.java index 434adea8a..154f9225a 100644 --- a/src/main/java/nextstep/member/application/MemberService.java +++ b/src/main/java/nextstep/member/application/MemberService.java @@ -1,18 +1,30 @@ package nextstep.member.application; +import nextstep.member.application.dto.FavoriteRequest; +import nextstep.member.application.dto.FavoriteResponse; import nextstep.member.application.dto.MemberRequest; import nextstep.member.application.dto.MemberResponse; -import nextstep.member.domain.LoginMember; -import nextstep.member.domain.Member; -import nextstep.member.domain.MemberRepository; +import nextstep.member.domain.*; +import nextstep.subway.applicaion.StationService; +import nextstep.subway.domain.Station; import org.springframework.stereotype.Service; +import java.util.List; +import java.util.stream.Collectors; + @Service public class MemberService { + private MemberRepository memberRepository; + private FavoriteRepository favoriteRepository; + private StationService stationService; - public MemberService(MemberRepository memberRepository) { + public MemberService(MemberRepository memberRepository, + FavoriteRepository favoriteRepository, + StationService stationService) { this.memberRepository = memberRepository; + this.favoriteRepository = favoriteRepository; + this.stationService = stationService; } public MemberResponse createMember(MemberRequest request) { @@ -53,4 +65,29 @@ public void deleteMemberOfMine(LoginMember loginMember) { Member member = memberRepository.findByEmail(loginMember.getEmail()).orElseThrow(RuntimeException::new); memberRepository.delete(member); } + + public FavoriteResponse createFavorite(LoginMember loginMember, FavoriteRequest favoriteRequest) { + Member member = memberRepository.findById(loginMember.getId()).orElseThrow(RuntimeException::new); + Station source = stationService.findById(favoriteRequest.getSource()); + Station target = stationService.findById(favoriteRequest.getTarget()); + Favorite favorite = new Favorite(member.getId(), source, target); + favoriteRepository.save(favorite); + + return FavoriteResponse.of(favorite); + } + + public List findFavoritesOfMine(LoginMember loginMember) { + Member member = memberRepository.findById(loginMember.getId()).orElseThrow(RuntimeException::new); + List favorites = favoriteRepository.findByMember(member.getId()); + + return favorites.stream() + .map(FavoriteResponse::of) + .collect(Collectors.toList()); + } + + public void deleteFavorite(LoginMember loginMember, Long favoriteId) { + Favorite favorite = favoriteRepository.findById(favoriteId).orElseThrow(RuntimeException::new); + + favoriteRepository.delete(favorite); + } } \ No newline at end of file diff --git a/src/main/java/nextstep/member/application/dto/FavoriteRequest.java b/src/main/java/nextstep/member/application/dto/FavoriteRequest.java new file mode 100644 index 000000000..09e9556e0 --- /dev/null +++ b/src/main/java/nextstep/member/application/dto/FavoriteRequest.java @@ -0,0 +1,15 @@ +package nextstep.member.application.dto; + +public class FavoriteRequest { + + private Long source; + private Long target; + + public Long getSource() { + return source; + } + + public Long getTarget() { + return target; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/member/application/dto/FavoriteResponse.java b/src/main/java/nextstep/member/application/dto/FavoriteResponse.java new file mode 100644 index 000000000..8065ada60 --- /dev/null +++ b/src/main/java/nextstep/member/application/dto/FavoriteResponse.java @@ -0,0 +1,37 @@ +package nextstep.member.application.dto; + +import nextstep.member.domain.Favorite; +import nextstep.subway.applicaion.dto.StationResponse; + +public class FavoriteResponse { + + private Long id; + private StationResponse source; + private StationResponse target; + + public static FavoriteResponse of(Favorite favorite) { + + return new FavoriteResponse( + favorite.getId(), + StationResponse.of(favorite.getSource()), + StationResponse.of(favorite.getTarget())); + } + + public FavoriteResponse(Long id, StationResponse source, StationResponse target) { + this.id = id; + this.source = source; + this.target = target; + } + + public Long getId() { + return id; + } + + public StationResponse getSource() { + return source; + } + + public StationResponse getTarget() { + return target; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/member/domain/Favorite.java b/src/main/java/nextstep/member/domain/Favorite.java new file mode 100644 index 000000000..2ecca2f50 --- /dev/null +++ b/src/main/java/nextstep/member/domain/Favorite.java @@ -0,0 +1,48 @@ +package nextstep.member.domain; + +import nextstep.subway.domain.Station; + +import javax.persistence.*; + +@Entity +public class Favorite { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @JoinColumn(name = "member_id") + private Long member; + + @ManyToOne(cascade = CascadeType.PERSIST) + @JoinColumn(name = "up_station_id") + private Station source; + + @ManyToOne(cascade = CascadeType.PERSIST) + @JoinColumn(name = "down_station_id") + private Station target; + + protected Favorite() {} + + public Favorite(Long memberId, Station source, Station target) { + this.member = memberId; + this.source = source; + this.target = target; + } + + public Long getId() { + return id; + } + + public Long getMember() { + return member; + } + + public Station getSource() { + return source; + } + + public Station getTarget() { + return target; + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/member/domain/FavoriteRepository.java b/src/main/java/nextstep/member/domain/FavoriteRepository.java new file mode 100644 index 000000000..030c61525 --- /dev/null +++ b/src/main/java/nextstep/member/domain/FavoriteRepository.java @@ -0,0 +1,11 @@ +package nextstep.member.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface FavoriteRepository extends JpaRepository { + + + List findByMember(Long member); +} \ No newline at end of file diff --git a/src/main/java/nextstep/member/domain/Favorites.java b/src/main/java/nextstep/member/domain/Favorites.java new file mode 100644 index 000000000..c11dc3a21 --- /dev/null +++ b/src/main/java/nextstep/member/domain/Favorites.java @@ -0,0 +1,27 @@ +package nextstep.member.domain; + +import javax.persistence.CascadeType; +import javax.persistence.Embeddable; +import javax.persistence.OneToMany; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Embeddable +public class Favorites { + + @OneToMany(mappedBy = "member", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true) + private List favorites = new ArrayList<>(); + + public void add(Favorite favorite) { + this.favorites.add(favorite); + } + + public void remove(Favorite favorite) { + this.favorites.remove(favorite); + } + + public List getFavorites() { + return Collections.unmodifiableList(favorites); + } +} \ No newline at end of file diff --git a/src/main/java/nextstep/member/domain/Member.java b/src/main/java/nextstep/member/domain/Member.java index 09ce656ed..041a9d91b 100644 --- a/src/main/java/nextstep/member/domain/Member.java +++ b/src/main/java/nextstep/member/domain/Member.java @@ -2,10 +2,8 @@ import nextstep.subway.domain.BaseEntity; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import javax.persistence.*; +import java.util.List; @Entity public class Member extends BaseEntity { diff --git a/src/main/java/nextstep/member/ui/MemberController.java b/src/main/java/nextstep/member/ui/MemberController.java index 96c4f7528..89b27fe4b 100644 --- a/src/main/java/nextstep/member/ui/MemberController.java +++ b/src/main/java/nextstep/member/ui/MemberController.java @@ -4,6 +4,8 @@ import nextstep.auth.context.SecurityContext; import nextstep.auth.context.SecurityContextHolder; import nextstep.member.application.MemberService; +import nextstep.member.application.dto.FavoriteRequest; +import nextstep.member.application.dto.FavoriteResponse; import nextstep.member.application.dto.MemberRequest; import nextstep.member.application.dto.MemberResponse; import nextstep.member.domain.LoginMember; @@ -11,6 +13,7 @@ import org.springframework.web.bind.annotation.*; import java.net.URI; +import java.util.List; @RestController public class MemberController { @@ -69,5 +72,32 @@ public ResponseEntity deleteMemberOfMine(@AuthenticationPrincipa return ResponseEntity.noContent().build(); } + + @PostMapping("/favorites") + public ResponseEntity createFavorite( + @AuthenticationPrincipal LoginMember loginMember, + @RequestBody FavoriteRequest request + ) { + FavoriteResponse favorite = memberService.createFavorite(loginMember, request); + + return ResponseEntity.created(URI.create("/favorites/" + favorite.getId())).build(); + } + + @GetMapping("/favorites") + public ResponseEntity> findFavoritesOfMine(@AuthenticationPrincipal LoginMember loginMember) { + List favoriteResponses = memberService.findFavoritesOfMine(loginMember); + + return ResponseEntity.ok().body(favoriteResponses); + } + + @DeleteMapping("/favorites/{favoriteId}") + public ResponseEntity deleteFavoriteOfMine( + @AuthenticationPrincipal LoginMember loginMember, + @PathVariable Long favoriteId + ) { + memberService.deleteFavorite(loginMember, favoriteId); + + return ResponseEntity.noContent().build(); + } } diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java new file mode 100644 index 000000000..efbe17e37 --- /dev/null +++ b/src/test/java/nextstep/subway/acceptance/FavoritesAcceptanceTest.java @@ -0,0 +1,131 @@ +package nextstep.subway.acceptance; + +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import nextstep.auth.authentication.AuthenticationToken; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; + +import java.util.HashMap; +import java.util.Map; + +import static nextstep.subway.acceptance.FavoritesSteps.*; +import static nextstep.subway.acceptance.LineSteps.지하철_노선_생성_요청; +import static nextstep.subway.acceptance.MemberSteps.*; +import static nextstep.subway.acceptance.StationSteps.지하철역_생성_요청; +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("즐겨찾기") +public class FavoritesAcceptanceTest extends AcceptanceTest { + + private static final String EMAIL = "email@email.com"; + private static final String PASSWORD = "password"; + private static final Integer AGE = 20; + + /** + * Given 지하철역 등록되어 있음 + * And 지하철 노선 등록되어 있음 + * And 지하철 노선에 지하철역 등록되어 있음 + * And 회원 등록되어 있음 + * And 로그인 되어있음 + */ + + private Long 강남역; + private Long 양재역; + private Long 신분당선; + private String accessToken; + + @BeforeEach + private void init() { + super.setUp(); + 강남역 = 지하철역_생성_요청("강남역").jsonPath().getLong("id"); + 양재역 = 지하철역_생성_요청("양재역").jsonPath().getLong("id"); + Map lineCreateParams = createLineCreateParams(강남역, 양재역); + 신분당선 = 지하철_노선_생성_요청(lineCreateParams).jsonPath().getLong("id"); + 회원_생성_요청(EMAIL, PASSWORD, AGE); + accessToken = 로그인_되어_있음(EMAIL, PASSWORD); + } + + /** + * When 즐겨찾기 생성을 요청 + * Then 즐겨찾기 생성됨 + */ + @DisplayName("즐겨찾기를 생성하다.") + @Test + void createFavorites() { + // when + ExtractableResponse result = 즐겨찾기_생성_요청(accessToken, 강남역, 양재역); + + // then + assertThat(result.response().statusCode()).isEqualTo(HttpStatus.CREATED.value()); + assertThat(result.header("Location")).isNotBlank(); + } + + /** + * given 즐겨찾기 생성 + * When 즐겨찾기 목록 조회 요청 + * Then 즐겨찾기 목록 조회됨 + */ + @DisplayName("즐겨찾기를 조회하다.") + @Test + void showFavorites() { + // given + 즐겨찾기_생성_요청(accessToken, 강남역, 양재역); + + // when + ExtractableResponse result = 즐겨찾기_목록_조회(accessToken); + + // then + assertThat(result.statusCode()).isEqualTo(HttpStatus.OK.value()); + assertThat(result.jsonPath().getList("id", Long.class)).hasSize(1).containsExactly(1L); + } + + /** + * given 즐겨찾기 생성 + * When 즐겨찾기 삭제 요청 + * Then 즐겨찾기 삭제됨 + */ + @DisplayName("즐가찾기를 삭제하다") + @Test + void removeFavorites() { + // given + 즐겨찾기_생성_요청(accessToken, 강남역, 양재역); + + // when + ExtractableResponse result = 즐겨찾기_삭제(accessToken, 1L); + + // then + assertThat(result.statusCode()).isEqualTo(HttpStatus.NO_CONTENT.value()); + } + + /** + * 비로그인 경우 401 Unauthorized 응답 + */ + @DisplayName("비로그인 즐겨찾기 기능을 사용할 수 없다.") + @Test + void isUnauthorizedByLogin() { + // given + 즐겨찾기_생성_요청(accessToken, 강남역, 양재역); + accessToken = ""; + + // when + ExtractableResponse result = 즐겨찾기_목록_조회(accessToken); + + // then + assertThat(result.statusCode()).isEqualTo(HttpStatus.UNAUTHORIZED.value()); + } + + private Map createLineCreateParams(Long upStationId, Long downStationId) { + Map lineCreateParams; + lineCreateParams = new HashMap<>(); + lineCreateParams.put("name", "신분당선"); + lineCreateParams.put("color", "bg-red-600"); + lineCreateParams.put("upStationId", upStationId + ""); + lineCreateParams.put("downStationId", downStationId + ""); + lineCreateParams.put("distance", 10 + ""); + + return lineCreateParams; + } +} diff --git a/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java b/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java new file mode 100644 index 000000000..bc4de5d3c --- /dev/null +++ b/src/test/java/nextstep/subway/acceptance/FavoritesSteps.java @@ -0,0 +1,49 @@ +package nextstep.subway.acceptance; + +import io.restassured.RestAssured; +import io.restassured.response.ExtractableResponse; +import io.restassured.response.Response; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +import java.util.HashMap; +import java.util.Map; + +public class FavoritesSteps { + + public static ExtractableResponse 즐겨찾기_생성_요청(final String accessToken, final Long source, final Long target) { + + Map favorites; + favorites = new HashMap<>(); + favorites.put("source", source + ""); + favorites.put("target", target + ""); + + return RestAssured.given().log().all() + .auth().oauth2(accessToken) + .body(favorites) + .contentType(MediaType.APPLICATION_JSON_VALUE) + .when().post("/favorites") + .then().log().all() + .statusCode(HttpStatus.CREATED.value()) + .extract(); + } + + public static ExtractableResponse 즐겨찾기_목록_조회(final String accessToken) { + + return RestAssured.given().log().all() + .auth().oauth2(accessToken) + .accept(MediaType.APPLICATION_JSON_VALUE) + .when().get("/favorites") + .then().log().all() + .extract(); + } + + public static ExtractableResponse 즐겨찾기_삭제(final String accessToken, final Long id) { + + return RestAssured + .given().log().all() + .auth().oauth2(accessToken) + .when().delete("/favorites/{favoriteId}", id) + .then().log().all().extract(); + } +} diff --git a/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java b/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java index 39f655ade..8c6766c87 100644 --- a/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java +++ b/src/test/java/nextstep/subway/unit/TokenAuthenticationInterceptorTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import nextstep.auth.authentication.AuthenticationToken; +import nextstep.auth.authentication.Authorizer; import nextstep.auth.authentication.TokenAuthenticationInterceptor; import nextstep.auth.context.Authentication; import nextstep.auth.token.JwtTokenProvider; @@ -34,6 +35,7 @@ class TokenAuthenticationInterceptorTest { public static final String JWT_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.ih1aovtQShabQ7l0cINw4k1fagApg3qLWiB8Kt59Lno"; private ObjectMapper objectMapper; + private Authorizer authorizor; @Mock private CustomUserDetailsService userDetailsService; @@ -44,12 +46,13 @@ class TokenAuthenticationInterceptorTest { @BeforeEach void init() { objectMapper = new ObjectMapper(); + authorizor = new Authorizer(userDetailsService); } @Test void convert() throws IOException { // given - TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper); + TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(jwtTokenProvider, objectMapper, authorizor); MockHttpServletRequest request = createMockRequest(); // when @@ -62,19 +65,19 @@ void convert() throws IOException { @Test void authenticate() { - TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper); + TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(jwtTokenProvider, objectMapper, authorizor); when(userDetailsService.loadUserByUsername(EMAIL)).thenReturn(new LoginMember(1L, EMAIL, PASSWORD, 20)); AuthenticationToken authenticationToken = new AuthenticationToken(EMAIL, PASSWORD); - Authentication authentication = interceptor.authenticate(authenticationToken); + Authentication authentication = authorizor.authenticate(authenticationToken); assertThat(authentication.getPrincipal()).isNotNull(); } @Test void preHandle() throws IOException, JSONException { - TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(userDetailsService, jwtTokenProvider, objectMapper); + TokenAuthenticationInterceptor interceptor = new TokenAuthenticationInterceptor(jwtTokenProvider, objectMapper, authorizor); when(userDetailsService.loadUserByUsername(EMAIL)).thenReturn(new LoginMember(1L, EMAIL, PASSWORD, 20)); when(jwtTokenProvider.createToken(anyString())).thenReturn(JWT_TOKEN);