From f56934eb2d07e80a947854ac4a5f0f504f3699fe Mon Sep 17 00:00:00 2001 From: SeoJimin1234 <113419021+SeoJimin1234@users.noreply.github.com> Date: Sun, 2 Feb 2025 17:03:00 +0900 Subject: [PATCH 1/9] Fix/ModifyMemberUpdate (#105) Co-authored-by: Kiara <80676180+2020147542@users.noreply.github.com> --- .../codeplay/controller/MemberController.java | 3 +++ .../codeplay/converter/MemberConverter.java | 2 +- .../umc/codeplay/dto/MemberRequestDTO.java | 7 +++--- .../umc/codeplay/dto/MemberResponseDTO.java | 1 - .../umc/codeplay/service/MemberService.java | 23 +++++++++++-------- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/main/java/umc/codeplay/controller/MemberController.java b/src/main/java/umc/codeplay/controller/MemberController.java index 2e01640..9bc5d4f 100644 --- a/src/main/java/umc/codeplay/controller/MemberController.java +++ b/src/main/java/umc/codeplay/controller/MemberController.java @@ -5,6 +5,7 @@ import lombok.RequiredArgsConstructor; +import io.swagger.v3.oas.annotations.Operation; import umc.codeplay.apiPayLoad.ApiResponse; import umc.codeplay.config.security.CustomUserDetails; import umc.codeplay.converter.MemberConverter; @@ -21,6 +22,7 @@ public class MemberController { private final MemberService memberService; private final MemberConverter memberConverter; + @Operation(summary = "유저 정보 업데이트(비밀번호 변경)", description = "기존 비밀번호, 새로운 비밀번호 입력") @PutMapping("/update") public ApiResponse updateMember( @AuthenticationPrincipal @@ -28,6 +30,7 @@ public ApiResponse updateMember( userDetails, // 현재 로그인된 사용자 정보, email로 조회하기 위해 customUserDetails 사용 @RequestBody MemberRequestDTO.UpdateMemberDTO requestDto) { + // userDetails.getUsername() -> 로그인된 사용자의 email Member updatedMember = memberService.updateMember(userDetails.getUsername(), requestDto); MemberResponseDTO.UpdateResultDTO responseDto = memberConverter.toUpdateResultDTO(updatedMember); diff --git a/src/main/java/umc/codeplay/converter/MemberConverter.java b/src/main/java/umc/codeplay/converter/MemberConverter.java index 75c735c..845ebde 100644 --- a/src/main/java/umc/codeplay/converter/MemberConverter.java +++ b/src/main/java/umc/codeplay/converter/MemberConverter.java @@ -39,7 +39,7 @@ public static MemberResponseDTO.LoginResultDTO toLoginResultDTO( public static MemberResponseDTO.UpdateResultDTO toUpdateResultDTO(Member member) { return MemberResponseDTO.UpdateResultDTO.builder() .email(member.getEmail()) - .profileUrl(member.getProfileUrl()) + // .profileUrl(member.getProfileUrl()) .build(); } } diff --git a/src/main/java/umc/codeplay/dto/MemberRequestDTO.java b/src/main/java/umc/codeplay/dto/MemberRequestDTO.java index bbcf034..6d27171 100644 --- a/src/main/java/umc/codeplay/dto/MemberRequestDTO.java +++ b/src/main/java/umc/codeplay/dto/MemberRequestDTO.java @@ -49,9 +49,10 @@ public static class CheckVerificationCodeDTO { @Setter public static class UpdateMemberDTO { - @NotBlank(message = "비밀번호는 필수 입력값입니다.") - String password; + @NotBlank(message = "기존 비밀번호는 필수 입력값입니다.") + String currentPassword; - String profileUrl; // 프로필 사진 URL + @NotBlank(message = "새로운 비밀번호는 필수 입력값입니다.") + String newPassword; } } diff --git a/src/main/java/umc/codeplay/dto/MemberResponseDTO.java b/src/main/java/umc/codeplay/dto/MemberResponseDTO.java index 265754f..88592d3 100644 --- a/src/main/java/umc/codeplay/dto/MemberResponseDTO.java +++ b/src/main/java/umc/codeplay/dto/MemberResponseDTO.java @@ -31,6 +31,5 @@ public static class LoginResultDTO { @AllArgsConstructor public static class UpdateResultDTO { String email; - String profileUrl; } } diff --git a/src/main/java/umc/codeplay/service/MemberService.java b/src/main/java/umc/codeplay/service/MemberService.java index 61f0739..d642b36 100644 --- a/src/main/java/umc/codeplay/service/MemberService.java +++ b/src/main/java/umc/codeplay/service/MemberService.java @@ -1,5 +1,6 @@ package umc.codeplay.service; +import java.security.InvalidParameterException; import jakarta.transaction.Transactional; import org.springframework.security.crypto.password.PasswordEncoder; @@ -65,21 +66,25 @@ public SocialStatus getSocialStatus(String email) { @Transactional public Member updateMember(String email, MemberRequestDTO.UpdateMemberDTO requestDto) { + // MemberRepository의 findByEmail()을 사용하여 회원 조회 Member member = memberRepository .findByEmail(email) .orElseThrow(() -> new IllegalArgumentException("해당 이메일의 회원이 존재하지 않습니다.")); - - // 비밀번호 변경(입력값이 있을 경우만) - if (requestDto.getPassword() != null && !requestDto.getPassword().isEmpty()) { - String encodedPassword = passwordEncoder.encode(requestDto.getPassword()); + System.out.println("console log checking"); + // 사용자 입력 값 + String newPassword = requestDto.getNewPassword(); + String currentPassword = requestDto.getCurrentPassword(); + // 기존 비밀번호 확인 + if (!passwordEncoder.matches(currentPassword, member.getPassword())) { + throw new InvalidParameterException("기존 비밀번호가 일치하지 않습니다."); + // 기존 비밀번호가 일치하고 새로운 비밀번호 입력값이 있을때 비밀번호 변경 + } else if (newPassword != null && !newPassword.isEmpty()) { + String encodedPassword = passwordEncoder.encode(newPassword); member.setPassword(encodedPassword); - } - - // 프로필 사진 변경(입력값이 있을 경우에만) - if (requestDto.getProfileUrl() != null && !requestDto.getProfileUrl().isEmpty()) { - member.setProfileUrl(requestDto.getProfileUrl()); + } else { + throw new InvalidParameterException("새로운 비밀번호를 입력해주세요."); } memberRepository.save(member); From 1db77247770aec5efb709e5d2848b46404b008ff Mon Sep 17 00:00:00 2001 From: SeoJimin1234 <113419021+SeoJimin1234@users.noreply.github.com> Date: Mon, 3 Feb 2025 18:09:35 +0900 Subject: [PATCH 2/9] feat/mypageHarmony/34 (#106) Co-authored-by: Kiara <80676180+2020147542@users.noreply.github.com> --- .../umc/codeplay/config/SecurityConfig.java | 1 + .../codeplay/controller/MemberController.java | 39 +++++++++++++++++++ .../codeplay/converter/MemberConverter.java | 21 ++++++++++ .../java/umc/codeplay/domain/Harmony.java | 1 + src/main/java/umc/codeplay/domain/Member.java | 1 + src/main/java/umc/codeplay/domain/Music.java | 1 + .../umc/codeplay/dto/MemberResponseDTO.java | 26 +++++++++++++ .../repository/HarmonyRepository.java | 14 +++++++ .../umc/codeplay/service/LikeService.java | 5 +++ .../umc/codeplay/service/MemberService.java | 16 ++++++++ 10 files changed, 125 insertions(+) create mode 100644 src/main/java/umc/codeplay/repository/HarmonyRepository.java diff --git a/src/main/java/umc/codeplay/config/SecurityConfig.java b/src/main/java/umc/codeplay/config/SecurityConfig.java index 7e54f03..604c77e 100644 --- a/src/main/java/umc/codeplay/config/SecurityConfig.java +++ b/src/main/java/umc/codeplay/config/SecurityConfig.java @@ -64,6 +64,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti "/health", "/health/s3", "/auth/**", + "/member/**", "/v2/api-docs", "/v3/api-docs", "/v3/api-docs/**", diff --git a/src/main/java/umc/codeplay/controller/MemberController.java b/src/main/java/umc/codeplay/controller/MemberController.java index 9bc5d4f..95d6f05 100644 --- a/src/main/java/umc/codeplay/controller/MemberController.java +++ b/src/main/java/umc/codeplay/controller/MemberController.java @@ -1,5 +1,8 @@ package umc.codeplay.controller; +import java.util.List; +import java.util.Optional; + import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; @@ -12,6 +15,7 @@ import umc.codeplay.domain.Member; import umc.codeplay.dto.MemberRequestDTO; import umc.codeplay.dto.MemberResponseDTO; +import umc.codeplay.repository.MemberRepository; import umc.codeplay.service.MemberService; @RestController @@ -21,6 +25,7 @@ public class MemberController { private final MemberService memberService; private final MemberConverter memberConverter; + private final MemberRepository memberRepository; @Operation(summary = "유저 정보 업데이트(비밀번호 변경)", description = "기존 비밀번호, 새로운 비밀번호 입력") @PutMapping("/update") @@ -37,4 +42,38 @@ public ApiResponse updateMember( return ApiResponse.onSuccess(responseDto); } + + @Operation(summary = "마이페이지 화성분석 탭 결과", description = "") + @GetMapping("/mypage/harmony") + public ApiResponse> getMyHarmony( + @AuthenticationPrincipal CustomUserDetails userDetails) { + + String email = userDetails.getUsername(); + // Member member = memberRepository.findByEmail(email); + Optional optionalMember = memberRepository.findByEmail(email); + if (optionalMember.isEmpty()) { + throw new RuntimeException("사용자를 찾을 수 없습니다."); + } + Member member = optionalMember.get(); + + List results = memberService.getMyHarmony(member); + + return ApiResponse.onSuccess(results); + } + + // @Operation(summary = "마이페이지 세션분리 탭 결과", description = "") + // @GetMapping("/mypage/tracks") + // public ApiResponse> getMyTracks() { + // + // } + + // @Operation(summary = "마이페이지 화성분석 탭에서 세션분리", description = "") + // @GetMapping("/mypage/harmonys/track") + // public ApiResponse<> + // + // + // @Operation(summary = "마이페이지 세션분리 탭에서 화성분석", description = "") + // @GetMapping("/mypage/tracks/harmony") + // public ApiResponse<> + } diff --git a/src/main/java/umc/codeplay/converter/MemberConverter.java b/src/main/java/umc/codeplay/converter/MemberConverter.java index 845ebde..b2659dc 100644 --- a/src/main/java/umc/codeplay/converter/MemberConverter.java +++ b/src/main/java/umc/codeplay/converter/MemberConverter.java @@ -2,13 +2,18 @@ import org.springframework.stereotype.Component; +import lombok.RequiredArgsConstructor; + +import umc.codeplay.domain.Harmony; import umc.codeplay.domain.Member; import umc.codeplay.domain.enums.Role; import umc.codeplay.domain.enums.SocialStatus; import umc.codeplay.dto.MemberRequestDTO; import umc.codeplay.dto.MemberResponseDTO; +import umc.codeplay.service.LikeService; @Component +@RequiredArgsConstructor public class MemberConverter { public static Member toMember(MemberRequestDTO.JoinDto request) { @@ -42,4 +47,20 @@ public static MemberResponseDTO.UpdateResultDTO toUpdateResultDTO(Member member) // .profileUrl(member.getProfileUrl()) .build(); } + + private final LikeService likeService; // LikeService 주입 + + public MemberResponseDTO.GetMyHarmonyDTO toGetMyHarmonyDTO(Harmony harmony, Member member) { + return MemberResponseDTO.GetMyHarmonyDTO.builder() + .musicId(harmony.getMusic().getId()) + .musicTitle(harmony.getMusic().getTitle()) + .createdAt(harmony.getCreatedAt()) + .harmonyKey(harmony.getHarmonyKey()) + .bpm(harmony.getBpm()) + .soundPressure(harmony.getSoundPressure()) + .isLiked( + likeService.isLikedByUser( + member, harmony.getMusic())) // LikeService에서 좋아요 여부 확인 + .build(); + } } diff --git a/src/main/java/umc/codeplay/domain/Harmony.java b/src/main/java/umc/codeplay/domain/Harmony.java index 51018ee..2bce7db 100644 --- a/src/main/java/umc/codeplay/domain/Harmony.java +++ b/src/main/java/umc/codeplay/domain/Harmony.java @@ -14,6 +14,7 @@ public class Harmony extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + // 추후 BigInteger로 변경 필요 private Long id; @Column(nullable = false, length = 50) diff --git a/src/main/java/umc/codeplay/domain/Member.java b/src/main/java/umc/codeplay/domain/Member.java index af6b44b..c67fbab 100644 --- a/src/main/java/umc/codeplay/domain/Member.java +++ b/src/main/java/umc/codeplay/domain/Member.java @@ -22,6 +22,7 @@ public class Member extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + // ToDo추후 BigInteger로 변환 private Long id; private String name; diff --git a/src/main/java/umc/codeplay/domain/Music.java b/src/main/java/umc/codeplay/domain/Music.java index 078e509..b0b96f8 100644 --- a/src/main/java/umc/codeplay/domain/Music.java +++ b/src/main/java/umc/codeplay/domain/Music.java @@ -18,6 +18,7 @@ public class Music extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + // 추후 BigInteger로 변경 필요 private Long id; @Column(nullable = false, length = 50) diff --git a/src/main/java/umc/codeplay/dto/MemberResponseDTO.java b/src/main/java/umc/codeplay/dto/MemberResponseDTO.java index 88592d3..59d50ac 100644 --- a/src/main/java/umc/codeplay/dto/MemberResponseDTO.java +++ b/src/main/java/umc/codeplay/dto/MemberResponseDTO.java @@ -1,5 +1,7 @@ package umc.codeplay.dto; +import java.time.LocalDateTime; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -32,4 +34,28 @@ public static class LoginResultDTO { public static class UpdateResultDTO { String email; } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class GetMyHarmonyDTO { + // 음원Id,음원제목, 생성 날짜, 키, bpm, 평균음압, 즐겨찾기 여부 + Long musicId; + String musicTitle; + LocalDateTime createdAt; + String harmonyKey; + Integer bpm; + Integer soundPressure; + Boolean isLiked; + } + + // @Builder + // @Getter + // @NoArgsConstructor + // @AllArgsConstructor + // public static class GetMyTrackDTO { + // // 음원제목, 생성일자, 즐겨찾기 여부 + // + // } } diff --git a/src/main/java/umc/codeplay/repository/HarmonyRepository.java b/src/main/java/umc/codeplay/repository/HarmonyRepository.java new file mode 100644 index 0000000..b38ef4c --- /dev/null +++ b/src/main/java/umc/codeplay/repository/HarmonyRepository.java @@ -0,0 +1,14 @@ +package umc.codeplay.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; + +import umc.codeplay.domain.Harmony; +import umc.codeplay.domain.Member; + +public interface HarmonyRepository extends JpaRepository { + + // 특정 사용자의 Harmony 리스트 조회 + List findByMusicMember(Member member); +} diff --git a/src/main/java/umc/codeplay/service/LikeService.java b/src/main/java/umc/codeplay/service/LikeService.java index 2fbb080..95f3b3c 100644 --- a/src/main/java/umc/codeplay/service/LikeService.java +++ b/src/main/java/umc/codeplay/service/LikeService.java @@ -66,4 +66,9 @@ public Music removeLike(String username, LikeRequestDTO.removeLikeRequestDTO req musicLikeRepository.delete(musicLike); return music; } + + @Transactional + public boolean isLikedByUser(Member member, Music music) { + return musicLikeRepository.existsByMemberAndMusic(member, music); + } } diff --git a/src/main/java/umc/codeplay/service/MemberService.java b/src/main/java/umc/codeplay/service/MemberService.java index d642b36..e27508f 100644 --- a/src/main/java/umc/codeplay/service/MemberService.java +++ b/src/main/java/umc/codeplay/service/MemberService.java @@ -1,6 +1,8 @@ package umc.codeplay.service; import java.security.InvalidParameterException; +import java.util.List; +import java.util.stream.Collectors; import jakarta.transaction.Transactional; import org.springframework.security.crypto.password.PasswordEncoder; @@ -11,10 +13,13 @@ import umc.codeplay.apiPayLoad.code.status.ErrorStatus; import umc.codeplay.apiPayLoad.exception.handler.GeneralHandler; import umc.codeplay.converter.MemberConverter; +import umc.codeplay.domain.Harmony; import umc.codeplay.domain.Member; import umc.codeplay.domain.enums.Role; import umc.codeplay.domain.enums.SocialStatus; import umc.codeplay.dto.MemberRequestDTO; +import umc.codeplay.dto.MemberResponseDTO; +import umc.codeplay.repository.HarmonyRepository; import umc.codeplay.repository.MemberRepository; @Service @@ -23,6 +28,8 @@ public class MemberService { private final MemberRepository memberRepository; private final PasswordEncoder passwordEncoder; + private final HarmonyRepository harmonyRepository; + private final MemberConverter memberConverter; public Member joinMember(MemberRequestDTO.JoinDto request) { @@ -90,4 +97,13 @@ public Member updateMember(String email, MemberRequestDTO.UpdateMemberDTO reques memberRepository.save(member); return member; } + + public List getMyHarmony(Member member) { + + List harmonies = harmonyRepository.findByMusicMember(member); + + return harmonies.stream() + .map(harmony -> memberConverter.toGetMyHarmonyDTO(harmony, member)) + .collect(Collectors.toList()); + } } From cfc5f6306dfa65baaafbb3cf601fc2d18fbe0e63 Mon Sep 17 00:00:00 2001 From: SeoJimin1234 <113419021+SeoJimin1234@users.noreply.github.com> Date: Mon, 3 Feb 2025 19:22:50 +0900 Subject: [PATCH 3/9] feat/deleteNameinMember/#107 (#108) Co-authored-by: Kiara <80676180+2020147542@users.noreply.github.com> --- .../java/umc/codeplay/controller/AuthController.java | 5 ++--- .../java/umc/codeplay/controller/OAuthController.java | 9 +++++---- .../java/umc/codeplay/converter/MemberConverter.java | 2 +- src/main/java/umc/codeplay/domain/Member.java | 1 + src/main/java/umc/codeplay/dto/MemberRequestDTO.java | 4 ++-- .../umc/codeplay/jwt/JwtAuthenticationFilter.java | 2 +- src/main/java/umc/codeplay/jwt/JwtUtil.java | 11 +++++------ src/main/java/umc/codeplay/service/MemberService.java | 4 ++-- 8 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/java/umc/codeplay/controller/AuthController.java b/src/main/java/umc/codeplay/controller/AuthController.java index a12c387..c10f3b1 100644 --- a/src/main/java/umc/codeplay/controller/AuthController.java +++ b/src/main/java/umc/codeplay/controller/AuthController.java @@ -46,7 +46,7 @@ public ApiResponse login( throw new GeneralHandler(ErrorStatus.AUTHORIZATION_METHOD_ERROR); } - // 아이디/비밀번호를 사용해 AuthenticationToken 생성 + // 이메일/비밀번호를 사용해 AuthenticationToken 생성 UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword()); @@ -56,7 +56,6 @@ public ApiResponse login( // Role 정보 가져오기 Collection authorities = authentication.getAuthorities(); - // 인증에 성공했다면, JWT 토큰 생성 후 반환 String token = jwtUtil.generateToken(authentication.getName(), authorities); String refreshToken = @@ -85,7 +84,7 @@ public ApiResponse refresh( // 리프레시 토큰 유효성 검사 if (jwtUtil.validateToken(refreshToken) && (jwtUtil.getTypeFromToken(refreshToken).equals("refresh"))) { - // 리프레시 토큰에서 사용자명 추출 + // 리프레시 토큰에서 사용자명 추출(email) String usernameFromToken = jwtUtil.getUsernameFromToken(refreshToken); if (!email.equals(usernameFromToken)) { diff --git a/src/main/java/umc/codeplay/controller/OAuthController.java b/src/main/java/umc/codeplay/controller/OAuthController.java index 6952339..25f489f 100644 --- a/src/main/java/umc/codeplay/controller/OAuthController.java +++ b/src/main/java/umc/codeplay/controller/OAuthController.java @@ -74,12 +74,12 @@ public ApiResponse OAuthCallback( String accessToken = (String) tokenResponse.get("access_token"); Map userInfo = requestOAuthUserInfo(accessToken, properties); String email = null; - String name = null; + // String name = null; switch (provider) { case "google" -> { // (3-a) 구글 UserInfo Endpoint 로 이메일, 프로필 등 조회 email = (String) userInfo.get("email"); - name = (String) userInfo.get("name"); + // name = (String) userInfo.get("name"); } case "kakao" -> { // (3-b) 카카오 UserInfo Endpoint 로 이메일, 프로필 등 조회 @@ -88,14 +88,15 @@ public ApiResponse OAuthCallback( Map kakaoProperties = (Map) userInfo.get("properties"); email = (String) kakaoAccount.get("email"); - name = (String) kakaoProperties.get("nickname"); + // name = (String) kakaoProperties.get("nickname"); } } // (4) 우리 DB에서 회원 조회 or 생성 Member member = memberService.findOrCreateOAuthMember( - email, name, SocialStatus.valueOf(provider.toUpperCase())); + email, SocialStatus.valueOf(provider.toUpperCase())); + // email, name, SocialStatus.valueOf(provider.toUpperCase())); // (5) JWTUtil 이용해서 Access/Refresh 토큰 발급 var authorities = List.of(new SimpleGrantedAuthority("ROLE_" + member.getRole().name())); diff --git a/src/main/java/umc/codeplay/converter/MemberConverter.java b/src/main/java/umc/codeplay/converter/MemberConverter.java index b2659dc..bf7c650 100644 --- a/src/main/java/umc/codeplay/converter/MemberConverter.java +++ b/src/main/java/umc/codeplay/converter/MemberConverter.java @@ -19,7 +19,7 @@ public class MemberConverter { public static Member toMember(MemberRequestDTO.JoinDto request) { return Member.builder() - .name(request.getName()) + // .name(request.getName()) .email(request.getEmail()) .password(request.getPassword()) .role(Role.USER) diff --git a/src/main/java/umc/codeplay/domain/Member.java b/src/main/java/umc/codeplay/domain/Member.java index c67fbab..2eaf30d 100644 --- a/src/main/java/umc/codeplay/domain/Member.java +++ b/src/main/java/umc/codeplay/domain/Member.java @@ -25,6 +25,7 @@ public class Member extends BaseEntity { // ToDo추후 BigInteger로 변환 private Long id; + // 사용 X private String name; private String password; diff --git a/src/main/java/umc/codeplay/dto/MemberRequestDTO.java b/src/main/java/umc/codeplay/dto/MemberRequestDTO.java index 6d27171..096efd6 100644 --- a/src/main/java/umc/codeplay/dto/MemberRequestDTO.java +++ b/src/main/java/umc/codeplay/dto/MemberRequestDTO.java @@ -11,8 +11,8 @@ public class MemberRequestDTO { @Getter public static class JoinDto { - @NotBlank(message = "이름은 필수 입력값입니다.") - String name; + // @NotBlank(message = "이름은 필수 입력값입니다.") + // String name; @NotBlank(message = "이메일은 필수 입력값입니다.") @Email(message = "이메일 형식이 아닙니다.") diff --git a/src/main/java/umc/codeplay/jwt/JwtAuthenticationFilter.java b/src/main/java/umc/codeplay/jwt/JwtAuthenticationFilter.java index fe2e1b7..3919d59 100644 --- a/src/main/java/umc/codeplay/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/umc/codeplay/jwt/JwtAuthenticationFilter.java @@ -36,7 +36,7 @@ protected void doFilterInternal( // 2. 토큰 유효성 검사 if (jwtUtil.validateToken(token) && (jwtUtil.getTypeFromToken(token).equals("access"))) { - // 3. 토큰에서 사용자 정보 추출 + // 3. 토큰에서 사용자 정보 추출(이메일) String username = jwtUtil.getUsernameFromToken(token); System.out.println(username); // String email = jwtUtil.getUsernameFromToken(token); diff --git a/src/main/java/umc/codeplay/jwt/JwtUtil.java b/src/main/java/umc/codeplay/jwt/JwtUtil.java index abd5290..0f58a05 100644 --- a/src/main/java/umc/codeplay/jwt/JwtUtil.java +++ b/src/main/java/umc/codeplay/jwt/JwtUtil.java @@ -26,8 +26,7 @@ private Key getSigningKey() { } // JWT 토큰 생성 - public String generateToken( - String username, Collection authorities) { + public String generateToken(String email, Collection authorities) { Date now = new Date(); List roleNames = @@ -38,7 +37,7 @@ public String generateToken( // 30분 만료 long EXPIRATION_TIME = 1000 * 60 * 30L; return Jwts.builder() - .setSubject(username) // 사용자 식별 정보 + .setSubject(email) // 사용자 식별 정보 .setIssuedAt(now) .claim("type", "access") .claim("roles", roleNames) // 발급 시간 @@ -47,7 +46,7 @@ public String generateToken( .compact(); } - // JWT 토큰에서 username 추출 + // JWT 토큰에서 username 추출(email 추출) public String getUsernameFromToken(String token) { return Jwts.parserBuilder() .setSigningKey(getSigningKey()) @@ -94,7 +93,7 @@ public List getRolesFromToken(String token) { // JWT 리프레시 토큰 생성 public String generateRefreshToken( - String username, Collection authorities) { + String email, Collection authorities) { Date now = new Date(); List roleNames = @@ -105,7 +104,7 @@ public String generateRefreshToken( // 1일 만료 long EXPIRATION_TIME = 1000 * 60 * 60 * 24L; return Jwts.builder() - .setSubject(username) // 사용자 식별 정보 + .setSubject(email) // 사용자 식별 정보 .setIssuedAt(now) .claim("type", "refresh") .claim("roles", roleNames) // 역할 정보 추가 diff --git a/src/main/java/umc/codeplay/service/MemberService.java b/src/main/java/umc/codeplay/service/MemberService.java index e27508f..1dfa02f 100644 --- a/src/main/java/umc/codeplay/service/MemberService.java +++ b/src/main/java/umc/codeplay/service/MemberService.java @@ -42,7 +42,7 @@ public Member joinMember(MemberRequestDTO.JoinDto request) { return memberRepository.save(newMember); } - public Member findOrCreateOAuthMember(String email, String name, SocialStatus socialStatus) { + public Member findOrCreateOAuthMember(String email, SocialStatus socialStatus) { Member member = memberRepository.findByEmail(email).orElse(null); @@ -50,7 +50,7 @@ public Member findOrCreateOAuthMember(String email, String name, SocialStatus so member = Member.builder() .email(email) - .name(name) + // .name(name) .role(Role.USER) .socialStatus(socialStatus) .build(); From 5589e5b3eedddb117547dc9e8103bf0b4cbb85a9 Mon Sep 17 00:00:00 2001 From: SeoJimin1234 <113419021+SeoJimin1234@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:10:18 +0900 Subject: [PATCH 4/9] Feat/track in mypage/#34 (#109) * feat/MyPageTrack/#34 * feat/mypageforTarck/#34 --------- Co-authored-by: Kiara <80676180+2020147542@users.noreply.github.com> --- .../codeplay/controller/MemberController.java | 34 +++++++++++++------ .../codeplay/converter/MemberConverter.java | 17 ++++++++++ .../umc/codeplay/dto/MemberResponseDTO.java | 26 +++++++++----- .../codeplay/repository/TrackRepository.java | 13 +++++++ .../umc/codeplay/service/MemberService.java | 12 +++++++ 5 files changed, 82 insertions(+), 20 deletions(-) create mode 100644 src/main/java/umc/codeplay/repository/TrackRepository.java diff --git a/src/main/java/umc/codeplay/controller/MemberController.java b/src/main/java/umc/codeplay/controller/MemberController.java index 95d6f05..956c637 100644 --- a/src/main/java/umc/codeplay/controller/MemberController.java +++ b/src/main/java/umc/codeplay/controller/MemberController.java @@ -61,19 +61,31 @@ public ApiResponse> getMyHarmony( return ApiResponse.onSuccess(results); } - // @Operation(summary = "마이페이지 세션분리 탭 결과", description = "") - // @GetMapping("/mypage/tracks") - // public ApiResponse> getMyTracks() { - // - // } + @Operation(summary = "마이페이지 세션분리 탭 결과", description = "") + @GetMapping("/mypage/track") + public ApiResponse> getMyTracks( + @AuthenticationPrincipal CustomUserDetails userDetails) { + + String email = userDetails.getUsername(); + + Optional optionalMember = memberRepository.findByEmail(email); + if (optionalMember.isEmpty()) { + throw new RuntimeException("사용자를 찾을 수 없습니다."); + } + Member member = optionalMember.get(); + + List results = memberService.getMyTrack(member); - // @Operation(summary = "마이페이지 화성분석 탭에서 세션분리", description = "") - // @GetMapping("/mypage/harmonys/track") - // public ApiResponse<> + return ApiResponse.onSuccess(results); + } + // + // @Operation(summary = "마이페이지 화성분석 탭에서 세션분리", description = "") + // @GetMapping("/mypage/harmonys/track") + // public ApiResponse<> // // - // @Operation(summary = "마이페이지 세션분리 탭에서 화성분석", description = "") - // @GetMapping("/mypage/tracks/harmony") - // public ApiResponse<> + // @Operation(summary = "마이페이지 세션분리 탭에서 화성분석", description = "") + // @GetMapping("/mypage/tracks/harmony") + // public ApiResponse<> } diff --git a/src/main/java/umc/codeplay/converter/MemberConverter.java b/src/main/java/umc/codeplay/converter/MemberConverter.java index bf7c650..52b83fb 100644 --- a/src/main/java/umc/codeplay/converter/MemberConverter.java +++ b/src/main/java/umc/codeplay/converter/MemberConverter.java @@ -6,6 +6,7 @@ import umc.codeplay.domain.Harmony; import umc.codeplay.domain.Member; +import umc.codeplay.domain.Track; import umc.codeplay.domain.enums.Role; import umc.codeplay.domain.enums.SocialStatus; import umc.codeplay.dto.MemberRequestDTO; @@ -52,6 +53,7 @@ public static MemberResponseDTO.UpdateResultDTO toUpdateResultDTO(Member member) public MemberResponseDTO.GetMyHarmonyDTO toGetMyHarmonyDTO(Harmony harmony, Member member) { return MemberResponseDTO.GetMyHarmonyDTO.builder() + .harmonyId(harmony.getId()) .musicId(harmony.getMusic().getId()) .musicTitle(harmony.getMusic().getTitle()) .createdAt(harmony.getCreatedAt()) @@ -63,4 +65,19 @@ public MemberResponseDTO.GetMyHarmonyDTO toGetMyHarmonyDTO(Harmony harmony, Memb member, harmony.getMusic())) // LikeService에서 좋아요 여부 확인 .build(); } + + public MemberResponseDTO.GetMyTrackDTO toGetMyTrackDTO(Track track, Member member) { + return MemberResponseDTO.GetMyTrackDTO.builder() + .trackId(track.getId()) + .musicId(track.getMusic().getId()) + .musicTitle(track.getMusic().getTitle()) + .createdAt(track.getCreatedAt()) + .guitarUrl(track.getGuitarUrl()) + .drumUrl(track.getDrumUrl()) + .keyoardUrl(track.getKeyboardUrl()) + .isLiked( + likeService.isLikedByUser( + member, track.getMusic())) // LikeService에서 좋아요 여부 확인 + .build(); + } } diff --git a/src/main/java/umc/codeplay/dto/MemberResponseDTO.java b/src/main/java/umc/codeplay/dto/MemberResponseDTO.java index 59d50ac..ad85fd1 100644 --- a/src/main/java/umc/codeplay/dto/MemberResponseDTO.java +++ b/src/main/java/umc/codeplay/dto/MemberResponseDTO.java @@ -40,7 +40,8 @@ public static class UpdateResultDTO { @NoArgsConstructor @AllArgsConstructor public static class GetMyHarmonyDTO { - // 음원Id,음원제목, 생성 날짜, 키, bpm, 평균음압, 즐겨찾기 여부 + // 화성분석Id,,음원Id,음원제목, 생성 날짜, 키, bpm, 평균음압, 즐겨찾기 여부 + Long harmonyId; Long musicId; String musicTitle; LocalDateTime createdAt; @@ -50,12 +51,19 @@ public static class GetMyHarmonyDTO { Boolean isLiked; } - // @Builder - // @Getter - // @NoArgsConstructor - // @AllArgsConstructor - // public static class GetMyTrackDTO { - // // 음원제목, 생성일자, 즐겨찾기 여부 - // - // } + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class GetMyTrackDTO { + // 세션 분리 id, 음원 id, 음원 제목, 생성일자, 좋아요여부, 기타 파일 url, 드럼 파일 url, 키보드파일 url + Long trackId; + Long musicId; + String musicTitle; + LocalDateTime createdAt; + Boolean isLiked; + String guitarUrl; + String drumUrl; + String keyoardUrl; + } } diff --git a/src/main/java/umc/codeplay/repository/TrackRepository.java b/src/main/java/umc/codeplay/repository/TrackRepository.java new file mode 100644 index 0000000..0e2ab96 --- /dev/null +++ b/src/main/java/umc/codeplay/repository/TrackRepository.java @@ -0,0 +1,13 @@ +package umc.codeplay.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; + +import umc.codeplay.domain.Member; +import umc.codeplay.domain.Track; + +public interface TrackRepository extends JpaRepository { + // 특정 사용자의 Track 리스트 조회 + List findByMusicMember(Member member); +} diff --git a/src/main/java/umc/codeplay/service/MemberService.java b/src/main/java/umc/codeplay/service/MemberService.java index 1dfa02f..9a56df6 100644 --- a/src/main/java/umc/codeplay/service/MemberService.java +++ b/src/main/java/umc/codeplay/service/MemberService.java @@ -15,12 +15,14 @@ import umc.codeplay.converter.MemberConverter; import umc.codeplay.domain.Harmony; import umc.codeplay.domain.Member; +import umc.codeplay.domain.Track; import umc.codeplay.domain.enums.Role; import umc.codeplay.domain.enums.SocialStatus; import umc.codeplay.dto.MemberRequestDTO; import umc.codeplay.dto.MemberResponseDTO; import umc.codeplay.repository.HarmonyRepository; import umc.codeplay.repository.MemberRepository; +import umc.codeplay.repository.TrackRepository; @Service @RequiredArgsConstructor @@ -30,6 +32,7 @@ public class MemberService { private final PasswordEncoder passwordEncoder; private final HarmonyRepository harmonyRepository; private final MemberConverter memberConverter; + private final TrackRepository trackRepository; public Member joinMember(MemberRequestDTO.JoinDto request) { @@ -106,4 +109,13 @@ public List getMyHarmony(Member member) { .map(harmony -> memberConverter.toGetMyHarmonyDTO(harmony, member)) .collect(Collectors.toList()); } + + public List getMyTrack(Member member) { + + List tracks = trackRepository.findByMusicMember(member); + + return tracks.stream() + .map(track -> memberConverter.toGetMyTrackDTO(track, member)) + .collect(Collectors.toList()); + } } From fa21725a6baab7ff9441bd87dfb7576fdca8f4bc Mon Sep 17 00:00:00 2001 From: Minhyung Kim Date: Thu, 6 Feb 2025 17:19:53 +0900 Subject: [PATCH 5/9] =?UTF-8?q?[fix]=20=EB=8B=89=EB=84=A4=EC=9E=84=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20(#111)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * name attribute deleted * minor fix --- .../java/umc/codeplay/controller/AuthController.java | 4 ++-- .../java/umc/codeplay/controller/OAuthController.java | 1 - .../java/umc/codeplay/converter/MemberConverter.java | 1 - src/main/java/umc/codeplay/domain/Member.java | 3 --- src/main/java/umc/codeplay/dto/MemberRequestDTO.java | 3 --- .../java/umc/codeplay/jwt/JwtAuthenticationFilter.java | 9 ++++----- src/main/java/umc/codeplay/jwt/JwtUtil.java | 4 ++-- src/main/java/umc/codeplay/service/MemberService.java | 1 - 8 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/main/java/umc/codeplay/controller/AuthController.java b/src/main/java/umc/codeplay/controller/AuthController.java index c10f3b1..0a22d2f 100644 --- a/src/main/java/umc/codeplay/controller/AuthController.java +++ b/src/main/java/umc/codeplay/controller/AuthController.java @@ -84,8 +84,8 @@ public ApiResponse refresh( // 리프레시 토큰 유효성 검사 if (jwtUtil.validateToken(refreshToken) && (jwtUtil.getTypeFromToken(refreshToken).equals("refresh"))) { - // 리프레시 토큰에서 사용자명 추출(email) - String usernameFromToken = jwtUtil.getUsernameFromToken(refreshToken); + // 리프레시 토큰에서 사용자명 추출 + String usernameFromToken = jwtUtil.getEmailFromToken(refreshToken); if (!email.equals(usernameFromToken)) { throw new GeneralHandler(ErrorStatus.INVALID_REFRESH_TOKEN); diff --git a/src/main/java/umc/codeplay/controller/OAuthController.java b/src/main/java/umc/codeplay/controller/OAuthController.java index 25f489f..0924963 100644 --- a/src/main/java/umc/codeplay/controller/OAuthController.java +++ b/src/main/java/umc/codeplay/controller/OAuthController.java @@ -96,7 +96,6 @@ public ApiResponse OAuthCallback( Member member = memberService.findOrCreateOAuthMember( email, SocialStatus.valueOf(provider.toUpperCase())); - // email, name, SocialStatus.valueOf(provider.toUpperCase())); // (5) JWTUtil 이용해서 Access/Refresh 토큰 발급 var authorities = List.of(new SimpleGrantedAuthority("ROLE_" + member.getRole().name())); diff --git a/src/main/java/umc/codeplay/converter/MemberConverter.java b/src/main/java/umc/codeplay/converter/MemberConverter.java index 52b83fb..64231a0 100644 --- a/src/main/java/umc/codeplay/converter/MemberConverter.java +++ b/src/main/java/umc/codeplay/converter/MemberConverter.java @@ -20,7 +20,6 @@ public class MemberConverter { public static Member toMember(MemberRequestDTO.JoinDto request) { return Member.builder() - // .name(request.getName()) .email(request.getEmail()) .password(request.getPassword()) .role(Role.USER) diff --git a/src/main/java/umc/codeplay/domain/Member.java b/src/main/java/umc/codeplay/domain/Member.java index 2eaf30d..48349b2 100644 --- a/src/main/java/umc/codeplay/domain/Member.java +++ b/src/main/java/umc/codeplay/domain/Member.java @@ -25,9 +25,6 @@ public class Member extends BaseEntity { // ToDo추후 BigInteger로 변환 private Long id; - // 사용 X - private String name; - private String password; private String email; diff --git a/src/main/java/umc/codeplay/dto/MemberRequestDTO.java b/src/main/java/umc/codeplay/dto/MemberRequestDTO.java index 096efd6..0266aac 100644 --- a/src/main/java/umc/codeplay/dto/MemberRequestDTO.java +++ b/src/main/java/umc/codeplay/dto/MemberRequestDTO.java @@ -11,9 +11,6 @@ public class MemberRequestDTO { @Getter public static class JoinDto { - // @NotBlank(message = "이름은 필수 입력값입니다.") - // String name; - @NotBlank(message = "이메일은 필수 입력값입니다.") @Email(message = "이메일 형식이 아닙니다.") String email; diff --git a/src/main/java/umc/codeplay/jwt/JwtAuthenticationFilter.java b/src/main/java/umc/codeplay/jwt/JwtAuthenticationFilter.java index 3919d59..08bd439 100644 --- a/src/main/java/umc/codeplay/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/umc/codeplay/jwt/JwtAuthenticationFilter.java @@ -36,10 +36,9 @@ protected void doFilterInternal( // 2. 토큰 유효성 검사 if (jwtUtil.validateToken(token) && (jwtUtil.getTypeFromToken(token).equals("access"))) { - // 3. 토큰에서 사용자 정보 추출(이메일) - String username = jwtUtil.getUsernameFromToken(token); - System.out.println(username); - // String email = jwtUtil.getUsernameFromToken(token); + // 3. 토큰에서 사용자 정보 추출 + String email = jwtUtil.getEmailFromToken(token); + System.out.println(email); List roles = jwtUtil.getRolesFromToken(token); List authorities = @@ -48,7 +47,7 @@ protected void doFilterInternal( .collect(Collectors.toList()); // CustomUserDetails 객체 생성 후 저장 - CustomUserDetails userDetails = new CustomUserDetails(username, "", authorities); + CustomUserDetails userDetails = new CustomUserDetails(email, "", authorities); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, authorities); diff --git a/src/main/java/umc/codeplay/jwt/JwtUtil.java b/src/main/java/umc/codeplay/jwt/JwtUtil.java index 0f58a05..b14d628 100644 --- a/src/main/java/umc/codeplay/jwt/JwtUtil.java +++ b/src/main/java/umc/codeplay/jwt/JwtUtil.java @@ -46,8 +46,8 @@ public String generateToken(String email, Collection .compact(); } - // JWT 토큰에서 username 추출(email 추출) - public String getUsernameFromToken(String token) { + // JWT 토큰에서 username 추출 + public String getEmailFromToken(String token) { return Jwts.parserBuilder() .setSigningKey(getSigningKey()) .build() diff --git a/src/main/java/umc/codeplay/service/MemberService.java b/src/main/java/umc/codeplay/service/MemberService.java index 9a56df6..a32a43c 100644 --- a/src/main/java/umc/codeplay/service/MemberService.java +++ b/src/main/java/umc/codeplay/service/MemberService.java @@ -53,7 +53,6 @@ public Member findOrCreateOAuthMember(String email, SocialStatus socialStatus) { member = Member.builder() .email(email) - // .name(name) .role(Role.USER) .socialStatus(socialStatus) .build(); From 2fffa0e4eb60bbb85c30ae7886135169b6d5841e Mon Sep 17 00:00:00 2001 From: SeoJimin1234 <113419021+SeoJimin1234@users.noreply.github.com> Date: Fri, 7 Feb 2025 23:16:46 +0900 Subject: [PATCH 6/9] feat/MypageSearch/#33 (#123) --- .../codeplay/controller/MemberController.java | 84 ++++++++++++++++--- .../codeplay/converter/MemberConverter.java | 2 +- .../umc/codeplay/dto/MemberRequestDTO.java | 7 ++ .../umc/codeplay/dto/MemberResponseDTO.java | 13 ++- .../repository/HarmonyRepository.java | 7 ++ .../codeplay/repository/MusicRepository.java | 5 +- .../codeplay/repository/TrackRepository.java | 7 ++ .../umc/codeplay/service/MemberService.java | 39 +++++++++ 8 files changed, 149 insertions(+), 15 deletions(-) diff --git a/src/main/java/umc/codeplay/controller/MemberController.java b/src/main/java/umc/codeplay/controller/MemberController.java index 956c637..ff383a6 100644 --- a/src/main/java/umc/codeplay/controller/MemberController.java +++ b/src/main/java/umc/codeplay/controller/MemberController.java @@ -13,9 +13,11 @@ import umc.codeplay.config.security.CustomUserDetails; import umc.codeplay.converter.MemberConverter; import umc.codeplay.domain.Member; +import umc.codeplay.domain.Music; import umc.codeplay.dto.MemberRequestDTO; import umc.codeplay.dto.MemberResponseDTO; import umc.codeplay.repository.MemberRepository; +import umc.codeplay.repository.MusicRepository; import umc.codeplay.service.MemberService; @RestController @@ -26,6 +28,7 @@ public class MemberController { private final MemberService memberService; private final MemberConverter memberConverter; private final MemberRepository memberRepository; + private final MusicRepository musicRepository; @Operation(summary = "유저 정보 업데이트(비밀번호 변경)", description = "기존 비밀번호, 새로운 비밀번호 입력") @PutMapping("/update") @@ -43,13 +46,13 @@ public ApiResponse updateMember( return ApiResponse.onSuccess(responseDto); } - @Operation(summary = "마이페이지 화성분석 탭 결과", description = "") + @Operation(summary = "마이페이지 화성분석 탭 결과", description = "로그인한 상태에서 마이페이지") @GetMapping("/mypage/harmony") public ApiResponse> getMyHarmony( @AuthenticationPrincipal CustomUserDetails userDetails) { String email = userDetails.getUsername(); - // Member member = memberRepository.findByEmail(email); + Optional optionalMember = memberRepository.findByEmail(email); if (optionalMember.isEmpty()) { throw new RuntimeException("사용자를 찾을 수 없습니다."); @@ -61,7 +64,7 @@ public ApiResponse> getMyHarmony( return ApiResponse.onSuccess(results); } - @Operation(summary = "마이페이지 세션분리 탭 결과", description = "") + @Operation(summary = "마이페이지 세션분리 탭 결과", description = "로그인한 상태에서 마이페이지") @GetMapping("/mypage/track") public ApiResponse> getMyTracks( @AuthenticationPrincipal CustomUserDetails userDetails) { @@ -78,14 +81,71 @@ public ApiResponse> getMyTracks( return ApiResponse.onSuccess(results); } - // - // @Operation(summary = "마이페이지 화성분석 탭에서 세션분리", description = "") - // @GetMapping("/mypage/harmonys/track") - // public ApiResponse<> - // - // - // @Operation(summary = "마이페이지 세션분리 탭에서 화성분석", description = "") - // @GetMapping("/mypage/tracks/harmony") - // public ApiResponse<> + @Operation(summary = "마이페이지 전체 검색", description = "파라미터 musicTitle에 음원 제목으로 검색") + @GetMapping("/mypage/search") + public ApiResponse getByMusicTitle( + @AuthenticationPrincipal CustomUserDetails userDetails, + @RequestParam String musicTitle) { + + // 현재 로그인한 사용자 검색 + String email = userDetails.getUsername(); + + Optional optionalMember = memberRepository.findByEmail(email); + if (optionalMember.isEmpty()) { + throw new RuntimeException("사용자를 찾을 수 없습니다."); + } + Member member = optionalMember.get(); + + Music music = musicRepository.findByTitle(musicTitle); + + MemberResponseDTO.GetAllByMusicTitleDTO results = + memberService.getAllByMusicTitle(member, music); + + return ApiResponse.onSuccess(results); + } + + @Operation(summary = "마이페이지 화성분석 검색", description = "파라미터 musicTitle에 음원 제목으로 검색") + @GetMapping("/mypage/harmony/search") + public ApiResponse> getHarmonyByMusicTitle( + @AuthenticationPrincipal CustomUserDetails userDetails, + @RequestParam String musicTitle) { + // 현재 로그인한 사용자 검색 + String email = userDetails.getUsername(); + + Optional optionalMember = memberRepository.findByEmail(email); + if (optionalMember.isEmpty()) { + throw new RuntimeException("사용자를 찾을 수 없습니다."); + } + Member member = optionalMember.get(); + + Music music = musicRepository.findByTitle(musicTitle); + + List results = + memberService.getHarmonyByMusicTitle(member, music); + + return ApiResponse.onSuccess(results); + } + + @Operation(summary = "마이페이지 세션분리 검색", description = "파라미터 musicTitle에 음원 제목으로 검색") + @GetMapping("/mypage/track/search") + public ApiResponse> getTrackByMusicTitle( + @AuthenticationPrincipal CustomUserDetails userDetails, + @RequestParam String musicTitle) { + // 현재 로그인한 사용자 검색 + String email = userDetails.getUsername(); + + Optional optionalMember = memberRepository.findByEmail(email); + if (optionalMember.isEmpty()) { + throw new RuntimeException("사용자를 찾을 수 없습니다."); + } + Member member = optionalMember.get(); + + Music music = musicRepository.findByTitle(musicTitle); + + List results = + memberService.getTrackByMusicTitle(member, music); + + return ApiResponse.onSuccess(results); + } } diff --git a/src/main/java/umc/codeplay/converter/MemberConverter.java b/src/main/java/umc/codeplay/converter/MemberConverter.java index 64231a0..ffd9bea 100644 --- a/src/main/java/umc/codeplay/converter/MemberConverter.java +++ b/src/main/java/umc/codeplay/converter/MemberConverter.java @@ -73,7 +73,7 @@ public MemberResponseDTO.GetMyTrackDTO toGetMyTrackDTO(Track track, Member membe .createdAt(track.getCreatedAt()) .guitarUrl(track.getGuitarUrl()) .drumUrl(track.getDrumUrl()) - .keyoardUrl(track.getKeyboardUrl()) + .keyboardUrl(track.getKeyboardUrl()) .isLiked( likeService.isLikedByUser( member, track.getMusic())) // LikeService에서 좋아요 여부 확인 diff --git a/src/main/java/umc/codeplay/dto/MemberRequestDTO.java b/src/main/java/umc/codeplay/dto/MemberRequestDTO.java index 0266aac..3623637 100644 --- a/src/main/java/umc/codeplay/dto/MemberRequestDTO.java +++ b/src/main/java/umc/codeplay/dto/MemberRequestDTO.java @@ -52,4 +52,11 @@ public static class UpdateMemberDTO { @NotBlank(message = "새로운 비밀번호는 필수 입력값입니다.") String newPassword; } + + @Getter + public static class SearchByMusicTitleDTO { + + @NotBlank(message = "음원 제목은 필수 입력값입니다.") + String musicTitle; + } } diff --git a/src/main/java/umc/codeplay/dto/MemberResponseDTO.java b/src/main/java/umc/codeplay/dto/MemberResponseDTO.java index ad85fd1..968caf4 100644 --- a/src/main/java/umc/codeplay/dto/MemberResponseDTO.java +++ b/src/main/java/umc/codeplay/dto/MemberResponseDTO.java @@ -1,6 +1,7 @@ package umc.codeplay.dto; import java.time.LocalDateTime; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; @@ -64,6 +65,16 @@ public static class GetMyTrackDTO { Boolean isLiked; String guitarUrl; String drumUrl; - String keyoardUrl; + String keyboardUrl; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class GetAllByMusicTitleDTO { + + private List harmonies; + private List tracks; } } diff --git a/src/main/java/umc/codeplay/repository/HarmonyRepository.java b/src/main/java/umc/codeplay/repository/HarmonyRepository.java index b38ef4c..d71e8e1 100644 --- a/src/main/java/umc/codeplay/repository/HarmonyRepository.java +++ b/src/main/java/umc/codeplay/repository/HarmonyRepository.java @@ -3,12 +3,19 @@ import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import umc.codeplay.domain.Harmony; import umc.codeplay.domain.Member; +import umc.codeplay.domain.Music; public interface HarmonyRepository extends JpaRepository { // 특정 사용자의 Harmony 리스트 조회 List findByMusicMember(Member member); + + // 특정 사용자의 Harmony 리스트 중 music의 harmony 조회 + @Query("SELECT h FROM Harmony h " + "WHERE h.music = :music AND h.music.member = :member") + List findByMusicAndMember(@Param("member") Member member, @Param("music") Music music); } diff --git a/src/main/java/umc/codeplay/repository/MusicRepository.java b/src/main/java/umc/codeplay/repository/MusicRepository.java index 4ecef4e..5527abd 100644 --- a/src/main/java/umc/codeplay/repository/MusicRepository.java +++ b/src/main/java/umc/codeplay/repository/MusicRepository.java @@ -4,4 +4,7 @@ import umc.codeplay.domain.Music; -public interface MusicRepository extends JpaRepository {} +public interface MusicRepository extends JpaRepository { + // 제목으로 음원 찾기 + Music findByTitle(String title); +} diff --git a/src/main/java/umc/codeplay/repository/TrackRepository.java b/src/main/java/umc/codeplay/repository/TrackRepository.java index 0e2ab96..19d0db3 100644 --- a/src/main/java/umc/codeplay/repository/TrackRepository.java +++ b/src/main/java/umc/codeplay/repository/TrackRepository.java @@ -3,11 +3,18 @@ import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import umc.codeplay.domain.Member; +import umc.codeplay.domain.Music; import umc.codeplay.domain.Track; public interface TrackRepository extends JpaRepository { // 특정 사용자의 Track 리스트 조회 List findByMusicMember(Member member); + + // 특정 사용자의 Harmony 리스트 중 music의 harmony 조회 + @Query("SELECT t FROM Track t " + "WHERE t.music = :music AND t.music.member = :member") + List findByMusicAndMember(@Param("member") Member member, @Param("music") Music music); } diff --git a/src/main/java/umc/codeplay/service/MemberService.java b/src/main/java/umc/codeplay/service/MemberService.java index a32a43c..8675514 100644 --- a/src/main/java/umc/codeplay/service/MemberService.java +++ b/src/main/java/umc/codeplay/service/MemberService.java @@ -15,6 +15,7 @@ import umc.codeplay.converter.MemberConverter; import umc.codeplay.domain.Harmony; import umc.codeplay.domain.Member; +import umc.codeplay.domain.Music; import umc.codeplay.domain.Track; import umc.codeplay.domain.enums.Role; import umc.codeplay.domain.enums.SocialStatus; @@ -117,4 +118,42 @@ public List getMyTrack(Member member) { .map(track -> memberConverter.toGetMyTrackDTO(track, member)) .collect(Collectors.toList()); } + + public MemberResponseDTO.GetAllByMusicTitleDTO getAllByMusicTitle(Member member, Music music) { + + List harmonies = harmonyRepository.findByMusicAndMember(member, music); + List tracks = trackRepository.findByMusicAndMember(member, music); + + List harmonyDTOs = + harmonies.stream() + .map(harmony -> memberConverter.toGetMyHarmonyDTO(harmony, member)) + .collect(Collectors.toList()); + + List trackDTOs = + tracks.stream() + .map(track -> memberConverter.toGetMyTrackDTO(track, member)) + .collect(Collectors.toList()); + + // DTO를 하나의 객체로 묶어서 반환 + return new MemberResponseDTO.GetAllByMusicTitleDTO(harmonyDTOs, trackDTOs); + } + + // 음원 제목으로 my harmony 검색 + public List getHarmonyByMusicTitle( + Member member, Music music) { + List harmonies = harmonyRepository.findByMusicAndMember(member, music); + + return harmonies.stream() + .map(harmony -> memberConverter.toGetMyHarmonyDTO(harmony, member)) + .collect(Collectors.toList()); + } + + // 음원 제목으로 my track 검색 + public List getTrackByMusicTitle(Member member, Music music) { + List tracks = trackRepository.findByMusicAndMember(member, music); + + return tracks.stream() + .map(track -> memberConverter.toGetMyTrackDTO(track, member)) + .collect(Collectors.toList()); + } } From 61c18c92e366f154249a7d4e42020d70277609f8 Mon Sep 17 00:00:00 2001 From: Kiara <80676180+2020147542@users.noreply.github.com> Date: Sun, 9 Feb 2025 16:33:06 +0900 Subject: [PATCH 7/9] =?UTF-8?q?[Feat]=20=ED=8C=8C=EC=9D=B4=EC=8D=AC=20?= =?UTF-8?q?=EB=A1=9C=EC=BB=AC=20=EC=84=9C=EB=B2=84=20=EA=B2=B0=EA=B3=BC=20?= =?UTF-8?q?db=EC=97=90=20=EB=B0=98=EC=98=81=20(#124)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Status: Open. #119 feat: task 저장 관련 작업 * #120 feat: 화성분리 결과 저장 * #199 feat: 트랙 분리 결과 저장 * #121 feat: 리믹스 결과 저장 * #121 chore: 주석과 definition 변경 * #121 controller 응답형식 변경 --- .../apiPayLoad/code/status/ErrorStatus.java | 7 +- .../codeplay/controller/FileController.java | 2 + .../controller/ModelResultController.java | 61 +++++++++++++++++ .../codeplay/converter/MemberConverter.java | 16 +++-- .../java/umc/codeplay/domain/Harmony.java | 45 +++++++++---- src/main/java/umc/codeplay/domain/Member.java | 2 +- src/main/java/umc/codeplay/domain/Music.java | 8 +-- src/main/java/umc/codeplay/domain/Remix.java | 66 +++++++++++++++++++ src/main/java/umc/codeplay/domain/Task.java | 37 +++++++++++ src/main/java/umc/codeplay/domain/Track.java | 46 ++++++++++--- .../umc/codeplay/domain/enums/JobType.java | 7 ++ .../codeplay/domain/enums/ProcessStatus.java | 9 +++ .../umc/codeplay/dto/MemberResponseDTO.java | 17 +++-- .../umc/codeplay/dto/ModelRequestDTO.java | 38 +++++++++++ .../umc/codeplay/dto/ModelResponseDTO.java | 33 ++++++++++ .../repository/HarmonyRepository.java | 6 ++ .../codeplay/repository/RemixRepository.java | 14 ++++ .../codeplay/repository/TaskRepository.java | 14 ++++ .../codeplay/repository/TrackRepository.java | 6 ++ .../umc/codeplay/service/ModelService.java | 57 ++++++++++++++++ 20 files changed, 450 insertions(+), 41 deletions(-) create mode 100644 src/main/java/umc/codeplay/controller/ModelResultController.java create mode 100644 src/main/java/umc/codeplay/domain/Remix.java create mode 100644 src/main/java/umc/codeplay/domain/Task.java create mode 100644 src/main/java/umc/codeplay/domain/enums/JobType.java create mode 100644 src/main/java/umc/codeplay/domain/enums/ProcessStatus.java create mode 100644 src/main/java/umc/codeplay/dto/ModelRequestDTO.java create mode 100644 src/main/java/umc/codeplay/dto/ModelResponseDTO.java create mode 100644 src/main/java/umc/codeplay/repository/RemixRepository.java create mode 100644 src/main/java/umc/codeplay/repository/TaskRepository.java create mode 100644 src/main/java/umc/codeplay/service/ModelService.java diff --git a/src/main/java/umc/codeplay/apiPayLoad/code/status/ErrorStatus.java b/src/main/java/umc/codeplay/apiPayLoad/code/status/ErrorStatus.java index 85ba965..c1d32e5 100644 --- a/src/main/java/umc/codeplay/apiPayLoad/code/status/ErrorStatus.java +++ b/src/main/java/umc/codeplay/apiPayLoad/code/status/ErrorStatus.java @@ -37,7 +37,12 @@ public enum ErrorStatus implements BaseErrorCode { LIKE_ALREADY_EXIST(HttpStatus.BAD_REQUEST, "LIKE401", "이미 좋아요 목록에 추가된 음원입니다."), EMAIL_SEND_ERROR(HttpStatus.BAD_REQUEST, "EMAIL400", "메일 발송에 실패하였습니다."), - EMAIL_CODE_ERROR(HttpStatus.BAD_REQUEST, "EMAIL401", "유효한 코드가 아닙니다."); + EMAIL_CODE_ERROR(HttpStatus.BAD_REQUEST, "EMAIL401", "유효한 코드가 아닙니다."), + + TASK_NOT_FOUND(HttpStatus.BAD_REQUEST, "TASK400", "해당 task를 찾을 수 없습니다."), + HARMONY_NOT_FOUND(HttpStatus.BAD_REQUEST, "HARMONY400", "해당 화성 분석 결과를 찾을 수 없습니다."), + TRACK_NOT_FOUND(HttpStatus.BAD_REQUEST, "TRACK400", "해당 트랙 분리 결과를 찾을 수 없습니다."), + REMIX_NOT_FOUND(HttpStatus.BAD_REQUEST, "REMIX400", "해당 리믹스 결과를 찾을 수 없습니다."); private final HttpStatus httpStatus; private final String code; diff --git a/src/main/java/umc/codeplay/controller/FileController.java b/src/main/java/umc/codeplay/controller/FileController.java index 76877af..d265b2b 100644 --- a/src/main/java/umc/codeplay/controller/FileController.java +++ b/src/main/java/umc/codeplay/controller/FileController.java @@ -9,6 +9,7 @@ import lombok.RequiredArgsConstructor; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import umc.codeplay.apiPayLoad.ApiResponse; import umc.codeplay.domain.enums.FileType; import umc.codeplay.dto.FileResponseDTO; @@ -19,6 +20,7 @@ @RestController @RequestMapping("/files") @RequiredArgsConstructor +@Tag(name = "file-controller", description = "모든 파일(사진, 음성)을 s3에 올릴 때 사용하는 api") public class FileController { private final FileService fileService; diff --git a/src/main/java/umc/codeplay/controller/ModelResultController.java b/src/main/java/umc/codeplay/controller/ModelResultController.java new file mode 100644 index 0000000..802dc62 --- /dev/null +++ b/src/main/java/umc/codeplay/controller/ModelResultController.java @@ -0,0 +1,61 @@ +package umc.codeplay.controller; + +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 lombok.RequiredArgsConstructor; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import umc.codeplay.apiPayLoad.ApiResponse; +import umc.codeplay.dto.ModelRequestDTO; +import umc.codeplay.dto.ModelResponseDTO; +import umc.codeplay.service.ModelService; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/python-model") +@Tag(name = "py-model-controller", description = "Python 로컬 서버의 분석 결과를 저장하는 API (프론트엔드 사용 X)") +public class ModelResultController { + + private final ModelService modelService; + + @Operation( + summary = "화성 분석 결과 저장", + description = "Python 서버의 화성 분석 결과를 저장합니다. 프론트엔드에서 사용하지 않습니다.") + @PostMapping("/harmony") + public ApiResponse updateHarmony( + @RequestBody ModelRequestDTO.HarmonyRequestDTO harmonyRequestDTO) { + + return ApiResponse.onSuccess( + ModelResponseDTO.HarmonyResponseDTO.builder() + .harmonyId(modelService.setHarmony(harmonyRequestDTO)) + .build()); + } + + @Operation( + summary = "세션 분리 결과 저장", + description = "Python 서버의 세션 분리 결과를 저장합니다. 프론트엔드에서 사용하지 않습니다.") + @PostMapping("/tracks") + public ApiResponse updateTrack( + @RequestBody ModelRequestDTO.TrackRequestDTO trackRequestDTO) { + + return ApiResponse.onSuccess( + ModelResponseDTO.TrackResponseDTO.builder() + .trackId(modelService.setTrack(trackRequestDTO)) + .build()); + } + + @Operation(summary = "리믹스 결과 저장", description = "Python 서버의 리믹스 결과를 저장합니다. 프론트엔드에서 사용하지 않습니다.") + @PostMapping("/remix") + public ApiResponse updateTrack( + @RequestBody ModelRequestDTO.RemixRequestDTO remixRequestDTO) { + + return ApiResponse.onSuccess( + ModelResponseDTO.RemixResponseDTO.builder() + .remixId(modelService.setRemix(remixRequestDTO)) + .build()); + } +} diff --git a/src/main/java/umc/codeplay/converter/MemberConverter.java b/src/main/java/umc/codeplay/converter/MemberConverter.java index ffd9bea..f9fdc27 100644 --- a/src/main/java/umc/codeplay/converter/MemberConverter.java +++ b/src/main/java/umc/codeplay/converter/MemberConverter.java @@ -54,11 +54,12 @@ public MemberResponseDTO.GetMyHarmonyDTO toGetMyHarmonyDTO(Harmony harmony, Memb return MemberResponseDTO.GetMyHarmonyDTO.builder() .harmonyId(harmony.getId()) .musicId(harmony.getMusic().getId()) - .musicTitle(harmony.getMusic().getTitle()) + .musicTitle(harmony.getTitle()) .createdAt(harmony.getCreatedAt()) - .harmonyKey(harmony.getHarmonyKey()) + .scale(harmony.getScale()) + .genre(harmony.getGenre()) .bpm(harmony.getBpm()) - .soundPressure(harmony.getSoundPressure()) + .voiceColor(harmony.getVoiceColor()) .isLiked( likeService.isLikedByUser( member, harmony.getMusic())) // LikeService에서 좋아요 여부 확인 @@ -69,11 +70,12 @@ public MemberResponseDTO.GetMyTrackDTO toGetMyTrackDTO(Track track, Member membe return MemberResponseDTO.GetMyTrackDTO.builder() .trackId(track.getId()) .musicId(track.getMusic().getId()) - .musicTitle(track.getMusic().getTitle()) + .musicTitle(track.getTitle()) .createdAt(track.getCreatedAt()) - .guitarUrl(track.getGuitarUrl()) - .drumUrl(track.getDrumUrl()) - .keyboardUrl(track.getKeyboardUrl()) + .bassUrl(track.getBassUrl()) + .instrumentalUrl(track.getInstrumentalUrl()) + .bassUrl(track.getBassUrl()) + .drumsUrl(track.getDrumsUrl()) .isLiked( likeService.isLikedByUser( member, track.getMusic())) // LikeService에서 좋아요 여부 확인 diff --git a/src/main/java/umc/codeplay/domain/Harmony.java b/src/main/java/umc/codeplay/domain/Harmony.java index 2bce7db..05e4ff5 100644 --- a/src/main/java/umc/codeplay/domain/Harmony.java +++ b/src/main/java/umc/codeplay/domain/Harmony.java @@ -2,38 +2,57 @@ import jakarta.persistence.*; -import lombok.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Comment; import umc.codeplay.domain.common.BaseEntity; @Entity @Getter -@Builder @NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor public class Harmony extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - // 추후 BigInteger로 변경 필요 + // TODO: 추후 BigInteger로 변환 private Long id; - @Column(nullable = false, length = 50) + @Column(nullable = false, length = 100) private String title; - private String harmonyKey; - + @Comment("스케일 = key") private String scale; - private String chord; + @Comment("장르") + private String genre; + @Comment("bpm 값") private Integer bpm; - private Integer soundPressure; - - @Column(columnDefinition = "TEXT") - private String harmonyUrl; + @Comment("음색") + private String voiceColor; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "music_id") + @Comment("입력 음악 ID") + @JoinColumn(name = "music_id", nullable = false) private Music music; + + @Builder + private Harmony(String scale, String genre, Integer bpm, String voiceColor, Music music) { + this.title = music.getTitle().split("-", 2)[1]; + this.scale = scale; + this.genre = genre; + this.bpm = bpm; + this.voiceColor = voiceColor; + this.music = music; + } + + public void updateHarmonyResult(String scale, Integer bpm, String genre, String voiceColor) { + this.scale = scale; + this.bpm = bpm; + this.genre = genre; + this.voiceColor = voiceColor; + } } diff --git a/src/main/java/umc/codeplay/domain/Member.java b/src/main/java/umc/codeplay/domain/Member.java index 48349b2..4470a37 100644 --- a/src/main/java/umc/codeplay/domain/Member.java +++ b/src/main/java/umc/codeplay/domain/Member.java @@ -22,7 +22,7 @@ public class Member extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - // ToDo추후 BigInteger로 변환 + // TODO: 추후 BigInteger로 변환 private Long id; private String password; diff --git a/src/main/java/umc/codeplay/domain/Music.java b/src/main/java/umc/codeplay/domain/Music.java index b0b96f8..1d5ea83 100644 --- a/src/main/java/umc/codeplay/domain/Music.java +++ b/src/main/java/umc/codeplay/domain/Music.java @@ -18,17 +18,17 @@ public class Music extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - // 추후 BigInteger로 변경 필요 + // TODO: 추후 BigInteger로 변환 private Long id; - @Column(nullable = false, length = 50) + @Column(nullable = false, length = 100) private String title; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id") + @JoinColumn(name = "member_id", nullable = false) private Member member; - @Column(columnDefinition = "TEXT") + @Column(columnDefinition = "TEXT", nullable = false) private String musicUrl; @OneToMany(mappedBy = "music", cascade = CascadeType.ALL) diff --git a/src/main/java/umc/codeplay/domain/Remix.java b/src/main/java/umc/codeplay/domain/Remix.java new file mode 100644 index 0000000..1e61e57 --- /dev/null +++ b/src/main/java/umc/codeplay/domain/Remix.java @@ -0,0 +1,66 @@ +package umc.codeplay.domain; + +import jakarta.persistence.*; + +import lombok.*; + +import org.hibernate.annotations.Comment; +import umc.codeplay.domain.common.BaseEntity; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Remix extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + // TODO: 추후 BigInteger로 변환 + private Long id; + + @Column(nullable = false, length = 100) + private String title; + + @Comment("음높이의 변화") + private Integer scaleModulation; + + @Comment("원래 템포에 대한 비율") + private Double tempoRatio; + + @Comment("리버브의 강도/정도") + private Double reverbAmount; + + @Comment("코러스 on/off") + private Boolean isChorusOn; + + @Column(columnDefinition = "TEXT") + @Comment("결과 s3 URL") + @Setter + private String resultMusicUrl; + + @ManyToOne(fetch = FetchType.LAZY) + @Comment("입력 음악 ID") + @JoinColumn(name = "music_id", nullable = false) + private Music music; + + @ManyToOne(fetch = FetchType.LAZY) + @Comment("이전 단계 리믹스 ID") + @JoinColumn(name = "parent_remix_id") + private Remix parentRemix; + + @Builder + public Remix( + Integer scaleModulation, + Double tempoRatio, + Double reverbAmount, + Boolean isChorusOn, + String resultMusicUrl, + Music music) { + this.title = music.getTitle().split("-", 2)[1]; + this.scaleModulation = scaleModulation; + this.tempoRatio = tempoRatio; + this.reverbAmount = reverbAmount; + this.isChorusOn = isChorusOn; + this.resultMusicUrl = resultMusicUrl; + this.music = music; + } +} diff --git a/src/main/java/umc/codeplay/domain/Task.java b/src/main/java/umc/codeplay/domain/Task.java new file mode 100644 index 0000000..8b64871 --- /dev/null +++ b/src/main/java/umc/codeplay/domain/Task.java @@ -0,0 +1,37 @@ +package umc.codeplay.domain; + +import jakarta.persistence.*; + +import lombok.*; + +import org.hibernate.annotations.Comment; +import umc.codeplay.domain.common.BaseEntity; +import umc.codeplay.domain.enums.JobType; +import umc.codeplay.domain.enums.ProcessStatus; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Task extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + // TODO: 추후 BigInteger로 변환 + private Long id; + + @Enumerated(EnumType.STRING) + @Comment("task 진행 상태") + @Builder.Default + private ProcessStatus status = ProcessStatus.REQUESTED; + + @Enumerated(EnumType.STRING) + @Comment("요청 기능 타입 (화성 분석, 세션 분리, 리믹스)") + @Column(nullable = false) + private JobType jobType; + + @Column(nullable = false) + @Comment("요청 기능의 데이터 id") + private Long jobId; +} diff --git a/src/main/java/umc/codeplay/domain/Track.java b/src/main/java/umc/codeplay/domain/Track.java index a211b86..a34ca28 100644 --- a/src/main/java/umc/codeplay/domain/Track.java +++ b/src/main/java/umc/codeplay/domain/Track.java @@ -2,34 +2,64 @@ import jakarta.persistence.*; -import lombok.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.Comment; import umc.codeplay.domain.common.BaseEntity; @Entity @Getter -@Builder @NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor public class Track extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + // TODO: 추후 BigInteger로 변환 private Long id; - @Column(nullable = false, length = 50) + @Column(nullable = false, length = 100) private String title; @Column(columnDefinition = "TEXT") - private String guitarUrl; + @Comment("보컬 url") + private String vocalUrl; @Column(columnDefinition = "TEXT") - private String drumUrl; + @Comment("반주 url") + private String instrumentalUrl; @Column(columnDefinition = "TEXT") - private String keyboardUrl; + @Comment("베이스 url") + private String bassUrl; + + @Column(columnDefinition = "TEXT") + @Comment("드럼 url") + private String drumsUrl; @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "music_id") + @Comment("입력 음악 ID") + @JoinColumn(name = "music_id", nullable = false) private Music music; + + @Builder + public Track( + String vocalUrl, String instrumentalUrl, String bassUrl, String drumsUrl, Music music) { + this.title = music.getTitle().split("-", 2)[1]; + this.vocalUrl = vocalUrl; + this.instrumentalUrl = instrumentalUrl; + this.bassUrl = bassUrl; + this.drumsUrl = drumsUrl; + this.music = music; + } + + public void updateTrackResult( + String vocalUrl, String instrumentalUrl, String bassUrl, String drumsUrl) { + this.vocalUrl = vocalUrl; + this.instrumentalUrl = instrumentalUrl; + this.bassUrl = bassUrl; + this.drumsUrl = drumsUrl; + } } diff --git a/src/main/java/umc/codeplay/domain/enums/JobType.java b/src/main/java/umc/codeplay/domain/enums/JobType.java new file mode 100644 index 0000000..389fc9d --- /dev/null +++ b/src/main/java/umc/codeplay/domain/enums/JobType.java @@ -0,0 +1,7 @@ +package umc.codeplay.domain.enums; + +public enum JobType { + Harmony, + Track, + Session +} diff --git a/src/main/java/umc/codeplay/domain/enums/ProcessStatus.java b/src/main/java/umc/codeplay/domain/enums/ProcessStatus.java new file mode 100644 index 0000000..e842122 --- /dev/null +++ b/src/main/java/umc/codeplay/domain/enums/ProcessStatus.java @@ -0,0 +1,9 @@ +package umc.codeplay.domain.enums; + +public enum ProcessStatus { + // todo: 그냥 예시로 적어둠 변경 필요 + REQUESTED, + ONGOING, + COMPLETED, + FAILED; +} diff --git a/src/main/java/umc/codeplay/dto/MemberResponseDTO.java b/src/main/java/umc/codeplay/dto/MemberResponseDTO.java index 968caf4..51100c3 100644 --- a/src/main/java/umc/codeplay/dto/MemberResponseDTO.java +++ b/src/main/java/umc/codeplay/dto/MemberResponseDTO.java @@ -41,14 +41,15 @@ public static class UpdateResultDTO { @NoArgsConstructor @AllArgsConstructor public static class GetMyHarmonyDTO { - // 화성분석Id,,음원Id,음원제목, 생성 날짜, 키, bpm, 평균음압, 즐겨찾기 여부 + // 화성분석Id, 음원Id, 음원제목, 생성 날짜, 키, bpm, 평균음압, 즐겨찾기 여부 Long harmonyId; Long musicId; String musicTitle; LocalDateTime createdAt; - String harmonyKey; + String scale; + String genre; Integer bpm; - Integer soundPressure; + String voiceColor; Boolean isLiked; } @@ -57,15 +58,17 @@ public static class GetMyHarmonyDTO { @NoArgsConstructor @AllArgsConstructor public static class GetMyTrackDTO { - // 세션 분리 id, 음원 id, 음원 제목, 생성일자, 좋아요여부, 기타 파일 url, 드럼 파일 url, 키보드파일 url + // 세션 분리 harmonyId, 음원 harmonyId, 음원 제목, 생성일자, 보컬 파일 url, 반주 url, 베이스 파일 url, 드럼 파일 url, + // 즐겨찾기 여부 Long trackId; Long musicId; String musicTitle; LocalDateTime createdAt; + String vocalUrl; + String instrumentalUrl; + String bassUrl; + String drumsUrl; Boolean isLiked; - String guitarUrl; - String drumUrl; - String keyboardUrl; } @Builder diff --git a/src/main/java/umc/codeplay/dto/ModelRequestDTO.java b/src/main/java/umc/codeplay/dto/ModelRequestDTO.java new file mode 100644 index 0000000..eabf3d0 --- /dev/null +++ b/src/main/java/umc/codeplay/dto/ModelRequestDTO.java @@ -0,0 +1,38 @@ +package umc.codeplay.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class ModelRequestDTO { + + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class HarmonyRequestDTO { + private Long taskId; + private String scale; + private Integer bpm; + private String genre; + private String voiceColor; + } + + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class TrackRequestDTO { + private Long taskId; + private String vocalUrl; + private String instrumentalUrl; + private String bassUrl; + private String drumsUrl; + } + + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class RemixRequestDTO { + private Long taskId; + private String resultMusicUrl; + } +} diff --git a/src/main/java/umc/codeplay/dto/ModelResponseDTO.java b/src/main/java/umc/codeplay/dto/ModelResponseDTO.java new file mode 100644 index 0000000..518d9e2 --- /dev/null +++ b/src/main/java/umc/codeplay/dto/ModelResponseDTO.java @@ -0,0 +1,33 @@ +package umc.codeplay.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class ModelResponseDTO { + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class HarmonyResponseDTO { + Long harmonyId; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class TrackResponseDTO { + Long trackId; + } + + @Builder + @Getter + @NoArgsConstructor + @AllArgsConstructor + public static class RemixResponseDTO { + Long remixId; + } +} diff --git a/src/main/java/umc/codeplay/repository/HarmonyRepository.java b/src/main/java/umc/codeplay/repository/HarmonyRepository.java index d71e8e1..2fa49dd 100644 --- a/src/main/java/umc/codeplay/repository/HarmonyRepository.java +++ b/src/main/java/umc/codeplay/repository/HarmonyRepository.java @@ -6,6 +6,8 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import umc.codeplay.apiPayLoad.code.status.ErrorStatus; +import umc.codeplay.apiPayLoad.exception.handler.GeneralHandler; import umc.codeplay.domain.Harmony; import umc.codeplay.domain.Member; import umc.codeplay.domain.Music; @@ -18,4 +20,8 @@ public interface HarmonyRepository extends JpaRepository { // 특정 사용자의 Harmony 리스트 중 music의 harmony 조회 @Query("SELECT h FROM Harmony h " + "WHERE h.music = :music AND h.music.member = :member") List findByMusicAndMember(@Param("member") Member member, @Param("music") Music music); + + default Harmony findByIdOrThrow(Long id) { + return findById(id).orElseThrow(() -> new GeneralHandler(ErrorStatus.HARMONY_NOT_FOUND)); + } } diff --git a/src/main/java/umc/codeplay/repository/RemixRepository.java b/src/main/java/umc/codeplay/repository/RemixRepository.java new file mode 100644 index 0000000..5a574a4 --- /dev/null +++ b/src/main/java/umc/codeplay/repository/RemixRepository.java @@ -0,0 +1,14 @@ +package umc.codeplay.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import umc.codeplay.apiPayLoad.code.status.ErrorStatus; +import umc.codeplay.apiPayLoad.exception.handler.GeneralHandler; +import umc.codeplay.domain.Remix; + +public interface RemixRepository extends JpaRepository { + + default Remix findByIdOrThrow(Long id) { + return findById(id).orElseThrow(() -> new GeneralHandler(ErrorStatus.REMIX_NOT_FOUND)); + } +} diff --git a/src/main/java/umc/codeplay/repository/TaskRepository.java b/src/main/java/umc/codeplay/repository/TaskRepository.java new file mode 100644 index 0000000..4924a90 --- /dev/null +++ b/src/main/java/umc/codeplay/repository/TaskRepository.java @@ -0,0 +1,14 @@ +package umc.codeplay.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import umc.codeplay.apiPayLoad.code.status.ErrorStatus; +import umc.codeplay.apiPayLoad.exception.handler.GeneralHandler; +import umc.codeplay.domain.Task; + +public interface TaskRepository extends JpaRepository { + + default Task findByIdOrThrow(Long id) { + return findById(id).orElseThrow(() -> new GeneralHandler(ErrorStatus.TASK_NOT_FOUND)); + } +} diff --git a/src/main/java/umc/codeplay/repository/TrackRepository.java b/src/main/java/umc/codeplay/repository/TrackRepository.java index 19d0db3..3b65354 100644 --- a/src/main/java/umc/codeplay/repository/TrackRepository.java +++ b/src/main/java/umc/codeplay/repository/TrackRepository.java @@ -6,6 +6,8 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import umc.codeplay.apiPayLoad.code.status.ErrorStatus; +import umc.codeplay.apiPayLoad.exception.handler.GeneralHandler; import umc.codeplay.domain.Member; import umc.codeplay.domain.Music; import umc.codeplay.domain.Track; @@ -17,4 +19,8 @@ public interface TrackRepository extends JpaRepository { // 특정 사용자의 Harmony 리스트 중 music의 harmony 조회 @Query("SELECT t FROM Track t " + "WHERE t.music = :music AND t.music.member = :member") List findByMusicAndMember(@Param("member") Member member, @Param("music") Music music); + + default Track findByIdOrThrow(Long id) { + return findById(id).orElseThrow(() -> new GeneralHandler(ErrorStatus.TRACK_NOT_FOUND)); + } } diff --git a/src/main/java/umc/codeplay/service/ModelService.java b/src/main/java/umc/codeplay/service/ModelService.java new file mode 100644 index 0000000..fd797a3 --- /dev/null +++ b/src/main/java/umc/codeplay/service/ModelService.java @@ -0,0 +1,57 @@ +package umc.codeplay.service; + +import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; + +import umc.codeplay.domain.Harmony; +import umc.codeplay.domain.Remix; +import umc.codeplay.domain.Task; +import umc.codeplay.domain.Track; +import umc.codeplay.dto.ModelRequestDTO; +import umc.codeplay.repository.HarmonyRepository; +import umc.codeplay.repository.RemixRepository; +import umc.codeplay.repository.TaskRepository; +import umc.codeplay.repository.TrackRepository; + +@Service +@RequiredArgsConstructor +public class ModelService { + + private final TaskRepository taskRepository; + private final HarmonyRepository harmonyRepository; + private final TrackRepository trackRepository; + private final RemixRepository remixRepository; + + public Long setHarmony(ModelRequestDTO.HarmonyRequestDTO harmonyResult) { + Task task = taskRepository.findByIdOrThrow(harmonyResult.getTaskId()); + Harmony harmony = harmonyRepository.findByIdOrThrow(task.getJobId()); + + harmony.updateHarmonyResult( + harmonyResult.getScale(), + harmonyResult.getBpm(), + harmonyResult.getGenre(), + harmonyResult.getVoiceColor()); + return harmonyRepository.save(harmony).getId(); + } + + public Long setTrack(ModelRequestDTO.TrackRequestDTO trackResult) { + Task task = taskRepository.findByIdOrThrow(trackResult.getTaskId()); + Track track = trackRepository.findByIdOrThrow(task.getJobId()); + + track.updateTrackResult( + trackResult.getVocalUrl(), + trackResult.getInstrumentalUrl(), + trackResult.getBassUrl(), + trackResult.getDrumsUrl()); + return trackRepository.save(track).getId(); + } + + public Long setRemix(ModelRequestDTO.RemixRequestDTO remixResult) { + Task task = taskRepository.findByIdOrThrow(remixResult.getTaskId()); + Remix remix = remixRepository.findByIdOrThrow(task.getJobId()); + + remix.setResultMusicUrl(remixResult.getResultMusicUrl()); + return remixRepository.save(remix).getId(); + } +} From 6c24cca8a70d8d643ba0ae06c987db4d138025ee Mon Sep 17 00:00:00 2001 From: Kiara <80676180+2020147542@users.noreply.github.com> Date: Sun, 9 Feb 2025 16:58:34 +0900 Subject: [PATCH 8/9] Update README.md (#126) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 9e9b9e2..0b96aa7 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ ## ⚡️변경사항 확인 바람⚡️ +- [Entity를 변경하고 다시 시작해도, db에 반영이 안되는 이유](https://github.com/UMC-CodePlay/CodePlay-BE/discussions/125) - [배포 과정 설명](https://github.com/UMC-CodePlay/CodePlay-BE/discussions/52) - [Docker를 이용한 DB 세팅 방법 확인하기](https://github.com/UMC-CodePlay/CodePlay-BE/discussions/28) - [자동 스타일 포맷터 사용법 바로가기](https://github.com/UMC-CodePlay/CodePlay-BE/discussions/3#discussioncomment-11796830) From edc50026f991a308f48070c2ffdcb4b74631771b Mon Sep 17 00:00:00 2001 From: Kiara <80676180+2020147542@users.noreply.github.com> Date: Sun, 9 Feb 2025 20:12:44 +0900 Subject: [PATCH 9/9] =?UTF-8?q?[Feat]=20=ED=8A=B9=EC=A0=95=20=EA=B8=B0?= =?UTF-8?q?=EA=B0=84=20=ED=9B=84=20=EC=9E=85=EB=A0=A5/=EA=B2=B0=EA=B3=BC?= =?UTF-8?q?=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=9E=90=EB=8F=99=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20(#130)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #122 삭제되도록 cascade 설정 및 entity 수정 * #122 mysql delete event script 추가 --- docker/local/deleteEvent.sql | 20 ++++++++++++++++ src/main/java/umc/codeplay/domain/Member.java | 18 ++++++++++---- src/main/java/umc/codeplay/domain/Music.java | 24 ++++++++++++++++--- src/main/java/umc/codeplay/domain/Remix.java | 13 ++++++++++ .../codeplay/repository/RemixRepository.java | 6 +++++ 5 files changed, 74 insertions(+), 7 deletions(-) create mode 100644 docker/local/deleteEvent.sql diff --git a/docker/local/deleteEvent.sql b/docker/local/deleteEvent.sql new file mode 100644 index 0000000..7f31c71 --- /dev/null +++ b/docker/local/deleteEvent.sql @@ -0,0 +1,20 @@ +create event clean_input_data on schedule + EVERY 1 DAY STARTS CURRENT_DATE + INTERVAL 1 DAY + enable + do + BEGIN + -- 2달 이상 지난 데이터 삭제 + DELETE FROM music WHERE DATE(created_at) < DATE_SUB(NOW(), INTERVAL 60 DAY); + DELETE FROM remix WHERE DATE(updated_at) < DATE_SUB(NOW(), INTERVAL 60 DAY); + END; + +create event clean_result_data on schedule + EVERY 1 DAY STARTS CURRENT_DATE + INTERVAL 1 DAY + enable + do + BEGIN + -- 2주 이상 지난 데이터 삭제 + DELETE FROM harmony WHERE DATE(updated_at) < DATE_SUB(NOW(), INTERVAL 14 DAY); + DELETE FROM track WHERE DATE(updated_at) < DATE_SUB(NOW(), INTERVAL 14 DAY); + UPDATE remix set deleted_at = now() WHERE DATE(updated_at) < DATE_SUB(NOW(), INTERVAL 14 DAY); + END; \ No newline at end of file diff --git a/src/main/java/umc/codeplay/domain/Member.java b/src/main/java/umc/codeplay/domain/Member.java index 4470a37..326ea4b 100644 --- a/src/main/java/umc/codeplay/domain/Member.java +++ b/src/main/java/umc/codeplay/domain/Member.java @@ -7,6 +7,8 @@ import lombok.*; import com.fasterxml.jackson.annotation.JsonIgnore; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; import umc.codeplay.domain.common.BaseEntity; import umc.codeplay.domain.enums.Role; import umc.codeplay.domain.enums.SocialStatus; @@ -25,8 +27,10 @@ public class Member extends BaseEntity { // TODO: 추후 BigInteger로 변환 private Long id; + @Column(nullable = false) private String password; + @Column(nullable = false) private String email; @Enumerated(EnumType.STRING) @@ -35,14 +39,20 @@ public class Member extends BaseEntity { @Enumerated(EnumType.STRING) private SocialStatus socialStatus; - public void encodePassword(String password) { - this.password = password; - } - @Column(columnDefinition = "TEXT") private String profileUrl; @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) + @OnDelete(action = OnDeleteAction.CASCADE) @JsonIgnore private List likeList = new ArrayList<>(); + + @OneToMany(mappedBy = "member", cascade = CascadeType.ALL) + @OnDelete(action = OnDeleteAction.CASCADE) + @JsonIgnore + private List musicList = new ArrayList<>(); + + public void encodePassword(String password) { + this.password = password; + } } diff --git a/src/main/java/umc/codeplay/domain/Music.java b/src/main/java/umc/codeplay/domain/Music.java index 1d5ea83..79e642b 100644 --- a/src/main/java/umc/codeplay/domain/Music.java +++ b/src/main/java/umc/codeplay/domain/Music.java @@ -7,6 +7,8 @@ import lombok.*; import com.fasterxml.jackson.annotation.JsonIgnore; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; import umc.codeplay.domain.common.BaseEntity; import umc.codeplay.domain.mapping.MusicLike; @@ -24,14 +26,30 @@ public class Music extends BaseEntity { @Column(nullable = false, length = 100) private String title; + @Column(columnDefinition = "TEXT", nullable = false) + private String musicUrl; + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id", nullable = false) private Member member; - @Column(columnDefinition = "TEXT", nullable = false) - private String musicUrl; - @OneToMany(mappedBy = "music", cascade = CascadeType.ALL) + @OnDelete(action = OnDeleteAction.CASCADE) @JsonIgnore private List likeList = new ArrayList<>(); + + @OneToMany(mappedBy = "music", cascade = CascadeType.ALL) + @OnDelete(action = OnDeleteAction.CASCADE) + @JsonIgnore + private List harmonies = new ArrayList<>(); + + @OneToMany(mappedBy = "music", cascade = CascadeType.ALL) + @OnDelete(action = OnDeleteAction.CASCADE) + @JsonIgnore + private List tracks = new ArrayList<>(); + + @OneToMany(mappedBy = "music", cascade = CascadeType.ALL) + @OnDelete(action = OnDeleteAction.CASCADE) + @JsonIgnore + private List remixes = new ArrayList<>(); } diff --git a/src/main/java/umc/codeplay/domain/Remix.java b/src/main/java/umc/codeplay/domain/Remix.java index 1e61e57..9afe704 100644 --- a/src/main/java/umc/codeplay/domain/Remix.java +++ b/src/main/java/umc/codeplay/domain/Remix.java @@ -1,10 +1,16 @@ package umc.codeplay.domain; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; import jakarta.persistence.*; import lombok.*; +import com.fasterxml.jackson.annotation.JsonIgnore; import org.hibernate.annotations.Comment; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; import umc.codeplay.domain.common.BaseEntity; @Entity @@ -37,6 +43,8 @@ public class Remix extends BaseEntity { @Setter private String resultMusicUrl; + private LocalDateTime deletedAt; + @ManyToOne(fetch = FetchType.LAZY) @Comment("입력 음악 ID") @JoinColumn(name = "music_id", nullable = false) @@ -47,6 +55,11 @@ public class Remix extends BaseEntity { @JoinColumn(name = "parent_remix_id") private Remix parentRemix; + @OneToMany(mappedBy = "parentRemix", cascade = CascadeType.ALL, orphanRemoval = true) + @OnDelete(action = OnDeleteAction.CASCADE) + @JsonIgnore + private List childRemixList = new ArrayList<>(); + @Builder public Remix( Integer scaleModulation, diff --git a/src/main/java/umc/codeplay/repository/RemixRepository.java b/src/main/java/umc/codeplay/repository/RemixRepository.java index 5a574a4..0c2f60f 100644 --- a/src/main/java/umc/codeplay/repository/RemixRepository.java +++ b/src/main/java/umc/codeplay/repository/RemixRepository.java @@ -11,4 +11,10 @@ public interface RemixRepository extends JpaRepository { default Remix findByIdOrThrow(Long id) { return findById(id).orElseThrow(() -> new GeneralHandler(ErrorStatus.REMIX_NOT_FOUND)); } + + /* + remix는 60일 동안 보관하지만, 한 remix의 결과가 다른 remix의 input이 되므로 60일 동안 보관하지만, + 다른 기능과 통일을 위해 14일이 지나면 마이페이지에서 보이지 않아야하므로 + TODO: 마이페이지에서 특정 사용자의 Remix 리스트 확인시, deleted_at이 있는 경우를 제외하고 검색 및 조회하기 + */ }