Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
gerry-mandering committed May 15, 2024
2 parents f874c23 + 86c778c commit ec20a08
Show file tree
Hide file tree
Showing 27 changed files with 342 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.example.dreamvalutbackend.config.handler.CommonLoginSuccessHandler;
import com.example.dreamvalutbackend.config.jwt.filter.JwtVerifyFilter;
import com.example.dreamvalutbackend.config.oauth2.service.OAuth2UserService;
import com.example.dreamvalutbackend.domain.user.repository.UserGenreRepository;
import com.example.dreamvalutbackend.redis.repository.TokenRepository;

import lombok.RequiredArgsConstructor;
Expand All @@ -39,6 +40,7 @@ public class SecurityConfig {

private final OAuth2UserService oAuth2UserService;
private final TokenRepository tokenRepository;
private final UserGenreRepository userGenreRepository;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
Expand Down Expand Up @@ -79,7 +81,7 @@ public JwtVerifyFilter jwtVerifyFilter() {
}
@Bean
public CommonLoginSuccessHandler commonLoginSuccessHandler() {
return new CommonLoginSuccessHandler(tokenRepository);
return new CommonLoginSuccessHandler(tokenRepository, userGenreRepository);
}
@Bean
public JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.example.dreamvalutbackend.config.jwt.utils.JwtConstants;
import com.example.dreamvalutbackend.config.jwt.utils.JwtUtils;
import com.example.dreamvalutbackend.domain.user.domain.UserDetailPrincipal;
import com.example.dreamvalutbackend.domain.user.repository.UserGenreRepository;
import com.example.dreamvalutbackend.redis.domain.Token;
import com.example.dreamvalutbackend.redis.repository.TokenRepository;
import com.google.gson.Gson;
Expand All @@ -15,6 +16,7 @@

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
Expand All @@ -34,6 +36,7 @@ public class CommonLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHan
private String frontendUrl;

private final TokenRepository tokenRepository;
private final UserGenreRepository userGenreRepository;

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
Expand All @@ -45,26 +48,32 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
String accessToken = JwtUtils.generateToken(responseMap, JwtConstants.ACCESS_EXP_TIME);
String refreshToken = JwtUtils.generateToken(responseMap, JwtConstants.REFRESH_EXP_TIME);

Long userId = principal.getUserId();
Token token = new Token(refreshToken, userId);
String userId = String.valueOf(principal.getUserId());
Token token = new Token(userId, refreshToken);
tokenRepository.save(token);

String targetUrl = determineTargetUrl(request, response, accessToken, refreshToken);
String targetUrl = determineTargetUrl(request, response, accessToken, refreshToken, Long.valueOf(userId));

getRedirectStrategy().sendRedirect(request, response, targetUrl);

}

protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response, String accessToken, String refreshToken) {
protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response, String accessToken, String refreshToken, Long userId) {
String redirectUri = request.getParameter("redirect_uri");
// if (redirectUri == null) {
// redirectUri = getDefaultTargetUrl();
// }

if (redirectUri == null) {
redirectUri = frontendUrl + "/genre_select"; // 기본값 설정
boolean hasGenres = userGenreRepository.existsByUser_UserId(userId);

if (hasGenres) {
redirectUri = frontendUrl + "/main";
} else {
redirectUri = frontendUrl + "/genre_select";
}



return UriComponentsBuilder.fromUriString(redirectUri)
.queryParam("accessToken", accessToken)
.queryParam("refreshToken", refreshToken)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,22 @@ public ResponseEntity<Map<String, Object>> refresh(@RequestHeader("Authorization

Map<String, Object> claims = JwtUtils.validateToken(refreshToken);
String userId = (String) claims.get("userId");
String storedToken = stringRedisTemplate.opsForValue().get("refreshToken:" + userId);
if (!refreshToken.equals(storedToken)) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Map.of("error", "Invalid refresh token"));
}
// #TODO: Redis 토큰 형식 오류 수정
// String storedToken = null;
// try {
// storedToken = stringRedisTemplate.opsForValue().get("refreshToken:" + userId);
// if (!refreshToken.equals(storedToken)) {
// return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Map.of("error", "Invalid refresh token"));
// }
// } catch (Exception e) {
// return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(Map.of("error", "Redis access error", "details" , e.getMessage()));
// }


String newAccessToken = JwtUtils.generateToken(claims, JwtConstants.ACCESS_EXP_TIME);
String newRefreshToken = refreshToken;
long expTime = JwtUtils.tokenRemainTime((Integer) claims.get("exp"));
// long expTime = JwtUtils.tokenRemainTime((Integer) claims.get("exp"));
long expTime = ((Number) claims.get("exp")).longValue();
if (expTime <= 60) {
newRefreshToken = JwtUtils.generateToken(claims, JwtConstants.REFRESH_EXP_TIME);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
@Slf4j
public class JwtVerifyFilter extends OncePerRequestFilter {

private static final String[] whitelist = { "/signUp", "/login", "/refresh", "/tracks", "/tracks/**", "/playlists",
private static final String[] whitelist = { "/signUp", "/login", "/tracks", "/tracks/**", "/playlists",
"/playlists/**", "/tags", "/tags/**", "/genres", "/genres/**", "/search", "/users", "/users/**" };

private static void checkAuthorizationHeader(String header) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

public class JwtConstants {
public static final String key = "DG3K2NG9lK3T2FLfnO283HO1NFLAy9FGJ23UM9Rv923YRV923HT";
public static final int ACCESS_EXP_TIME = 600; // 10분
public static final int REFRESH_EXP_TIME = 600 * 24; // 24시간
public static final int ACCESS_EXP_TIME = 30; // 30분
public static final int REFRESH_EXP_TIME = 60 * 24 ; // 24시간

public static final String JWT_HEADER = "Authorization";
public static final String JWT_TYPE = "Bearer ";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public static Map<String, Object> validateToken(String token) {
.parseClaimsJws(token) // 파싱 및 검증, 실패 시 에러
.getBody();
}catch (ExpiredJwtException expiredJwtException) {
throw new AuthenticationServiceException("토큰이 만료되었습니다", expiredJwtException);
throw new CustomExpiredJwtException("토큰이 만료되었습니다", expiredJwtException);
} catch(Exception e){
throw new CustomJwtException("Error");
}
Expand All @@ -90,8 +90,10 @@ public static Map<String, Object> validateToken(String token) {
public static boolean isExpired(String token) {
try {
validateToken(token);
} catch (CustomExpiredJwtException e) {
return true;
} catch (Exception e) {
return (e instanceof CustomExpiredJwtException);

}
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;

import io.swagger.v3.core.jackson.ModelResolver;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
Expand Down Expand Up @@ -45,4 +49,9 @@ private Info apiInfo() {
.description("DreamVault API")
.version("1.0.0");
}

@Bean
public ModelResolver modelResolver(ObjectMapper objectMapper) {
return new ModelResolver(objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.dreamvalutbackend.domain.like.service;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.data.domain.Page;
Expand Down Expand Up @@ -41,6 +42,10 @@ public LikeResponseDto addLike(LikeCreateRequestDto likeCreateRequestDto) {
Track track = trackRepository.findById(likeCreateRequestDto.getTrackId())
.orElseThrow(() -> new IllegalArgumentException("trackId가 존재하지 않습니다"));

Optional<Like> existingLike = likeRepository.findByUserAndTrack(user, track);

existingLike.ifPresent(like -> likeRepository.delete(like));

Like like = Like.builder()
.user(user)
.track(track)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,12 @@ public ResponseEntity<Page<UserCreateTrackResponseDto>> getUserCreatedPlaylists(

@GetMapping("/users/followed")
public ResponseEntity<Page<UserCreateTrackResponseDto>> getFollowedUserPlaylists(
@RequestParam String type,
@AuthenticationPrincipal UserDetailPrincipal userDetailPrincipal,
@PageableDefault(page = 0, size = 6, sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {

Long userId = userDetailPrincipal.getUserId();
Page<UserCreateTrackResponseDto> followedPlaylists = playlistService.findFollowedUserTrack(userId, pageable);
Page<UserCreateTrackResponseDto> followedPlaylists = playlistService.findFollowedUserTrack(userId, type, pageable);

return ResponseEntity.ok(followedPlaylists);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,31 @@ public class PlaylistWithTracksResponseDto {
private String ownerName;
private Boolean isPublic;
private Boolean isCurated;
private Boolean isFollow;
private Boolean isOwner;
private Page<TrackResponseDto> tracks;

@Builder
public PlaylistWithTracksResponseDto(Long playlistId, String playlistName, String ownerName, Boolean isPublic,
Boolean isCurated, Boolean isOwner, Page<TrackResponseDto> tracks) {
Boolean isCurated, Boolean isFollow, Boolean isOwner, Page<TrackResponseDto> tracks) {
this.playlistId = playlistId;
this.playlistName = playlistName;
this.ownerName = ownerName;
this.isPublic = isPublic;
this.isCurated = isCurated;
this.isFollow = isFollow;
this.isOwner = isOwner;
this.tracks = tracks;
}

public static PlaylistWithTracksResponseDto toDto(Playlist playlist, Page<TrackResponseDto> tracks, Boolean isOwner) {
public static PlaylistWithTracksResponseDto toDto(Playlist playlist, Page<TrackResponseDto> tracks, Boolean isOwner, Boolean isFollow) {
return PlaylistWithTracksResponseDto.builder()
.playlistId(playlist.getId())
.playlistName(playlist.getPlaylistName())
.ownerName(playlist.getUser().getDisplayName())
.isPublic(playlist.getIsPublic())
.isCurated(playlist.getIsCurated())
.isFollow(isFollow)
.isOwner(isOwner)
.tracks(tracks)
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.dreamvalutbackend.domain.playlist.repository;

import java.util.List;
import java.util.Optional;

import org.springframework.data.domain.Page;
Expand All @@ -18,5 +19,6 @@ public interface MyPlaylistRepository extends JpaRepository<MyPlaylist, Long> {

Optional<MyPlaylist> findByUserAndPlaylist(User user, Playlist playlist);

Page<MyPlaylist> findAllByUser_UserId(Long userId, Pageable pageable);
List<MyPlaylist> findAllByUser_UserId(Long userId);

}
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package com.example.dreamvalutbackend.domain.playlist.repository;

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;

import com.example.dreamvalutbackend.domain.playlist.domain.Playlist;

public interface PlaylistRepository extends JpaRepository<Playlist, Long> {
public interface PlaylistRepository extends JpaRepository<Playlist, Long>, PlaylistRepositoryCustom {

Page<Playlist> findByIsCuratedTrue(Pageable pageable);

Page<Playlist> findByIsCuratedFalseAndIsPublicTrue(Pageable pageable);

Page<Playlist> findAllByUser_UserId(Long userId, Pageable pageable);


Page<Playlist> findAllByIdInAndIsCurated(List<Long> ids, Boolean isCurated, Pageable pageable);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.example.dreamvalutbackend.domain.playlist.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import com.example.dreamvalutbackend.domain.playlist.domain.Playlist;


public interface PlaylistRepositoryCustom {
Page<Playlist> findUnionOfCreatedAndFollowedPlaylists(Long userId, Pageable pageable);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.example.dreamvalutbackend.domain.playlist.repository;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;

import com.example.dreamvalutbackend.domain.playlist.domain.Playlist;
import com.example.dreamvalutbackend.domain.playlist.domain.QMyPlaylist;
import com.example.dreamvalutbackend.domain.playlist.domain.QPlaylist;
import com.querydsl.jpa.impl.JPAQueryFactory;

import jakarta.persistence.EntityManager;

public class PlaylistRepositoryImpl implements PlaylistRepositoryCustom {

private final JPAQueryFactory queryFactory;

@Autowired
public PlaylistRepositoryImpl(EntityManager em) {
this.queryFactory = new JPAQueryFactory(em);
}

@Override
public Page<Playlist> findUnionOfCreatedAndFollowedPlaylists(Long userId, Pageable pageable) {
QPlaylist playlist = QPlaylist.playlist;
QMyPlaylist myPlaylist = QMyPlaylist.myPlaylist;

List<Long> createdPlaylistIds = queryFactory
.select(playlist.id)
.from(playlist)
.where(playlist.user.userId.eq(userId))
.fetch();

List<Long> followedPlaylistIds = queryFactory
.select(myPlaylist.playlist.id)
.from(myPlaylist)
.where(myPlaylist.user.userId.eq(userId))
.fetch();

Set<Long> unionIds = new HashSet<>(createdPlaylistIds);
unionIds.addAll(followedPlaylistIds);

List<Playlist> result = queryFactory
.selectFrom(playlist)
.where(playlist.id.in(unionIds))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();

long total = queryFactory
.selectFrom(playlist)
.where(playlist.id.in(unionIds))
.fetchCount();

return new PageImpl<>(result, pageable, total);

}



}
Loading

0 comments on commit ec20a08

Please sign in to comment.