-
Notifications
You must be signed in to change notification settings - Fork 0
[FEAT] 팔로우 리스트 조회 API 개발 #102
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package team.wego.wegobackend.common.config; | ||
|
|
||
| import com.querydsl.jpa.impl.JPAQueryFactory; | ||
| import jakarta.persistence.EntityManager; | ||
| import jakarta.persistence.PersistenceContext; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
|
|
||
| @Configuration | ||
| public class QuerydslConfig { | ||
|
|
||
| @PersistenceContext | ||
| private EntityManager entityManager; | ||
|
|
||
| @Bean | ||
| public JPAQueryFactory jpaQueryFactory() { | ||
| return new JPAQueryFactory(entityManager); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package team.wego.wegobackend.common.support; | ||
|
|
||
| import jakarta.persistence.EntityManager; | ||
| import jakarta.transaction.Transactional; | ||
| import org.springframework.boot.ApplicationArguments; | ||
| import org.springframework.boot.ApplicationRunner; | ||
| import org.springframework.context.annotation.Configuration; | ||
| import org.springframework.context.annotation.Profile; | ||
| import team.wego.wegobackend.common.security.Role; | ||
| import team.wego.wegobackend.user.domain.Follow; | ||
| import team.wego.wegobackend.user.domain.User; | ||
|
|
||
| /** | ||
| * local 테스트 데이터 초기화를 위한 설정 | ||
| * */ | ||
| @Configuration | ||
| @Profile("local") | ||
| public class LocalDataInitializer implements ApplicationRunner { | ||
|
|
||
| private final EntityManager em; | ||
|
|
||
| public LocalDataInitializer(EntityManager em) { | ||
| this.em = em; | ||
| } | ||
|
|
||
| @Override | ||
| @Transactional | ||
| public void run(ApplicationArguments args) throws Exception { | ||
| // test user ~100 | ||
| for(long i = 0; i <= 100; i++) { | ||
| em.persist(User.builder() | ||
| .email("user" + i + "@test.com") | ||
| .password("1q2w3e4r!") | ||
| .nickName("user" + i) | ||
| .role(Role.ROLE_USER) | ||
| .build() | ||
| ); | ||
| } | ||
|
|
||
| // user1 → user2~50 | ||
| for (long i = 2; i <= 50; i++) { | ||
| em.persist(new Follow( | ||
| em.getReference(User.class, 1L), | ||
| em.getReference(User.class, i) | ||
| )); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package team.wego.wegobackend.user.application.dto.response; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public record FollowListResponse(List<FollowResponse> items, Long nextCursor) { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package team.wego.wegobackend.user.application.dto.response; | ||
|
|
||
| import com.querydsl.core.annotations.QueryProjection; | ||
| import lombok.Getter; | ||
|
|
||
| @Getter | ||
| public class FollowResponse { | ||
|
|
||
| private final Long followId; //cursor | ||
| private final Long userId; | ||
| private final String profileImage; | ||
| private final String nickname; | ||
| private final String profileMessage; | ||
|
|
||
| @QueryProjection | ||
| public FollowResponse( | ||
| Long followId, | ||
| Long userId, | ||
| String profileImage, | ||
| String nickname, | ||
| String profileMessage | ||
| ) { | ||
| this.followId = followId; | ||
| this.userId = userId; | ||
| this.profileImage = profileImage; | ||
| this.nickname = nickname; | ||
| this.profileMessage = profileMessage; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,13 @@ | ||
| package team.wego.wegobackend.user.presentation; | ||
|
|
||
| import jakarta.validation.Valid; | ||
| import jakarta.validation.constraints.Max; | ||
| import jakarta.validation.constraints.Min; | ||
| import java.time.LocalDateTime; | ||
| import lombok.RequiredArgsConstructor; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.MediaType; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.security.core.annotation.AuthenticationPrincipal; | ||
| import org.springframework.web.bind.annotation.DeleteMapping; | ||
|
|
@@ -25,6 +28,7 @@ | |
| import team.wego.wegobackend.user.application.UserService; | ||
| import team.wego.wegobackend.user.application.dto.request.ProfileUpdateRequest; | ||
| import team.wego.wegobackend.user.application.dto.response.AvailabilityResponse; | ||
| import team.wego.wegobackend.user.application.dto.response.FollowListResponse; | ||
| import team.wego.wegobackend.user.application.dto.response.UserInfoResponse; | ||
|
|
||
| @Slf4j | ||
|
|
@@ -53,7 +57,7 @@ public ResponseEntity<ApiResponse<UserInfoResponse>> profile(@PathVariable Long | |
| /** | ||
| * 프로필 이미지 변경 | ||
| * */ | ||
| @PatchMapping("/profile-image") | ||
| @PatchMapping(value = "/profile-image", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) | ||
| public ResponseEntity<ApiResponse<UserInfoResponse>> profileImage( | ||
| @AuthenticationPrincipal CustomUserDetails userDetails, | ||
| @RequestPart("file") MultipartFile file | ||
|
|
@@ -131,6 +135,23 @@ public ResponseEntity<ApiResponse<String>> unFollow( | |
| .body(ApiResponse.success(200, "팔로우 취소 성공")); | ||
| } | ||
|
|
||
| /** | ||
| * 팔로우 리스트 조회 | ||
| * */ | ||
| @GetMapping("/{userId}/follow") | ||
| public ResponseEntity<ApiResponse<FollowListResponse>> followList( | ||
| @PathVariable Long userId, //다른 유저 조회를 위한 파라메터 | ||
| @RequestParam(required = false) Long cursor, | ||
| @RequestParam(defaultValue = "20") @Min(1) @Max(100) Integer size | ||
| ) { | ||
|
Comment on lines
+141
to
+146
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n src/main/java/team/wego/wegobackend/user/presentation/UserController.java | head -20Repository: WeGo-Together/WeGo_BackEnd Length of output: 1201 🏁 Script executed: rg -n "@Validated|@RestController|@RequestMapping" src/main/java/team/wego/wegobackend/user/presentation/UserController.java | head -20Repository: WeGo-Together/WeGo_BackEnd Length of output: 125 🏁 Script executed: sed -n '30,45p' src/main/java/team/wego/wegobackend/user/presentation/UserController.javaRepository: WeGo-Together/WeGo_BackEnd Length of output: 587 클래스에
클래스 선언부에 +import org.springframework.validation.annotation.Validated;
+
@Slf4j
@RestController
@RequiredArgsConstructor
+@Validated
@RequestMapping("/api/v1/users")
public class UserController implements UserControllerDocs {
🤖 Prompt for AI Agents |
||
|
|
||
| FollowListResponse response = followService.followList(userId, cursor, size); | ||
|
|
||
| return ResponseEntity | ||
| .status(HttpStatus.OK) | ||
| .body(ApiResponse.success(200, response)); | ||
| } | ||
|
|
||
| /** | ||
| * 이메일 중복검사 | ||
| * */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package team.wego.wegobackend.user.repository; | ||
|
|
||
| import java.util.List; | ||
| import team.wego.wegobackend.user.application.dto.response.FollowResponse; | ||
|
|
||
| public interface FollowRepositoryCustom { | ||
|
|
||
| List<FollowResponse> findFollowingList( | ||
| Long followerId, | ||
| Long cursorFollowId, | ||
| int size | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| package team.wego.wegobackend.user.repository; | ||
|
|
||
| import com.querydsl.core.types.dsl.BooleanExpression; | ||
| import com.querydsl.jpa.impl.JPAQueryFactory; | ||
| import java.util.List; | ||
| import lombok.RequiredArgsConstructor; | ||
| import team.wego.wegobackend.user.application.dto.response.FollowResponse; | ||
| import team.wego.wegobackend.user.application.dto.response.QFollowResponse; | ||
| import team.wego.wegobackend.user.domain.QFollow; | ||
| import team.wego.wegobackend.user.domain.QUser; | ||
|
|
||
| @RequiredArgsConstructor | ||
| public class FollowRepositoryImpl implements FollowRepositoryCustom{ | ||
|
|
||
| private final JPAQueryFactory jpaQueryFactory; | ||
|
|
||
| @Override | ||
| public List<FollowResponse> findFollowingList( | ||
| Long followerId, | ||
| Long cursorFollowId, | ||
| int size | ||
| ) { | ||
|
|
||
| QFollow follow = QFollow.follow; | ||
| QUser user = QUser.user; | ||
|
|
||
| return jpaQueryFactory | ||
| .select(new QFollowResponse( | ||
| follow.id, | ||
| user.id, | ||
| user.profileImage, | ||
| user.nickName, | ||
| user.profileMessage | ||
| )) | ||
| .from(follow) | ||
| .join(follow.followee, user) | ||
| .where( | ||
| follow.follower.id.eq(followerId), | ||
| ItCursor(cursorFollowId) | ||
| ) | ||
| .orderBy(follow.id.desc()) //최신 팔로우 순 | ||
| .limit(size) | ||
| .fetch(); | ||
| } | ||
|
|
||
| private BooleanExpression ItCursor(Long cursorFollowId) { | ||
| return cursorFollowId == null | ||
| ? null | ||
| : QFollow.follow.id.lt(cursorFollowId); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: WeGo-Together/WeGo_BackEnd
Length of output: 175
🏁 Script executed:
Repository: WeGo-Together/WeGo_BackEnd
Length of output: 497
🏁 Script executed:
Repository: WeGo-Together/WeGo_BackEnd
Length of output: 406
QueryDSL 5.1.0에 SQL/HQL 인젝션 취약점(CVE-2024-49203) 발견
현재 사용 중인 QueryDSL 5.1.0에 CVE-2024-49203 취약점이 있습니다(2024년 11월 공개). 이는 JPAQuery의 orderBy에서 SQL/HQL 인젝션을 허용하는 취약점입니다. 신뢰할 수 없는 입력값을 orderBy에 직접 사용하지 않는다면 즉시적인 위험은 낮지만, 5.1.0은 패치 버전이 없으므로 최신 버전으로 업그레이드하는 것을 권장합니다.
🤖 Prompt for AI Agents