Skip to content

Commit 8279f66

Browse files
authored
Merge pull request #73 from Team-Shaka/feature/72
✨ Feat: 내 프로필 조회, 내 프로필 수정, 트리하우스 생성 기능 구현
2 parents 0bb6e9d + 52c7573 commit 8279f66

File tree

18 files changed

+347
-89
lines changed

18 files changed

+347
-89
lines changed

src/main/java/treehouse/server/api/branch/business/BranchService.java

+1-70
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public BranchResponseDTO.getMemberBranchView getMemberBranchView(User user, Long
4747
List<Branch> branches = branchQueryAdapter.findAllByTreeHouse(treeHouse); // 트리하우스 내 모든 브랜치 조회
4848
Member member = memberQueryAdapter.findByUserAndTreehouse(user, treeHouse); // 현재 로그인한 트리하우스 멤버
4949
Long rootId = member.getId(); // 현재 로그인한 트리하우스 멤버의 ID
50-
BranchResponseDTO.ShortestPathResult shortestPathResult = findShortestDistance(branches, rootId, targetMemberId); // 최단 거리 계산
50+
BranchResponseDTO.ShortestPathResult shortestPathResult = BranchUtil.findShortestDistance(branches, rootId, targetMemberId); // 최단 거리 계산
5151

5252
// 최단 거리 결과를 이용해 브랜치 뷰 생성
5353
// Node 정보 생성
@@ -91,73 +91,4 @@ public BranchResponseDTO.getCompleteBranchView getCompleteBranchView(User user,
9191
// 브랜치 뷰 생성
9292
return BranchMapper.toCompleteBranchView(nodes, links);
9393
}
94-
95-
/**
96-
* 두 멤버 사이의 가장 짧은 거리를 계산하여 정수값으로 니다.
97-
* @param treeHouse
98-
* @param rootId // 시작 멤버 ID
99-
* @param leafId // 끝(대상) 멤버 ID
100-
* @return 두 멤버 사이의 가장 짧은 거리
101-
*/
102-
103-
public Integer calculateBranchDegree(TreeHouse treeHouse, Long rootId, Long leafId) {
104-
// 두 멤버 사이의 모든 Branch 엔티티를 찾습니다.
105-
List<Branch> branches = branchQueryAdapter.findAllByTreeHouse(treeHouse);
106-
107-
// Branch 목록을 사용하여 최단 거리를 계산합니다.
108-
int shortestDistance = findShortestDistance(branches, rootId, leafId).getDistance();
109-
110-
return shortestDistance;
111-
}
112-
113-
/**
114-
* BFS 알고리즘을 이용해 두 멤버 사이의 가장 짧은 거리를 계산합니다.
115-
* @param branches
116-
* @param startMemberId
117-
* @param endMemberId
118-
* @return 두 멤버 사이의 가장 짧은 거리
119-
*/
120-
121-
public BranchResponseDTO.ShortestPathResult findShortestDistance(List<Branch> branches, Long startMemberId, Long endMemberId) {
122-
Map<Long, List<Long>> adjacencyList = new HashMap<>();
123-
Map<Long, Long> prev = new HashMap<>();
124-
Set<Long> visited = new HashSet<>();
125-
Queue<Long> queue = new LinkedList<>();
126-
127-
// 각 멤버 ID를 기준으로 연결된 Branch를 매핑
128-
for (Branch branch : branches) {
129-
adjacencyList.computeIfAbsent(branch.getRoot().getId(), k -> new ArrayList<>()).add(branch.getLeaf().getId());
130-
adjacencyList.computeIfAbsent(branch.getLeaf().getId(), k -> new ArrayList<>()).add(branch.getRoot().getId());
131-
}
132-
133-
queue.add(startMemberId);
134-
visited.add(startMemberId);
135-
prev.put(startMemberId, null); // 시작 노드의 선행자는 없음
136-
137-
while (!queue.isEmpty()) {
138-
Long current = queue.poll();
139-
if (current.equals(endMemberId)) {
140-
break; // 목표 노드에 도달
141-
}
142-
for (Long neighbor : adjacencyList.getOrDefault(current, Collections.emptyList())) {
143-
if (!visited.contains(neighbor)) {
144-
visited.add(neighbor);
145-
queue.add(neighbor);
146-
prev.put(neighbor, current);
147-
}
148-
}
149-
}
150-
151-
// 경로 복원 및 결과 생성
152-
List<Long> path = new ArrayList<>();
153-
Long current = endMemberId;
154-
while (current != null) {
155-
path.add(current);
156-
current = prev.get(current);
157-
}
158-
Collections.reverse(path); // 경로를 역순으로 뒤집어 정상 순서로 만듦
159-
160-
int distance = path.size() - 1; // 거리는 경로의 길이에서 1을 뺀 값
161-
return BranchMapper.toShortestPathResult(distance, path);
162-
}
16394
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package treehouse.server.api.branch.business;
2+
3+
import treehouse.server.api.branch.presentation.dto.BranchResponseDTO;
4+
import treehouse.server.global.entity.branch.Branch;
5+
6+
import java.util.*;
7+
8+
public class BranchUtil {
9+
10+
/**
11+
* 두 멤버 사이의 가장 짧은 거리를 계산하여 정수값으로 니다.
12+
* @param rootId // 시작 멤버 ID
13+
* @param leafId // 끝(대상) 멤버 ID
14+
* @return 두 멤버 사이의 가장 짧은 거리
15+
*/
16+
17+
public static Integer calculateBranchDegree(List<Branch> branches, Long rootId, Long leafId) {
18+
// Branch 목록을 사용하여 최단 거리를 계산합니다.
19+
int shortestDistance = findShortestDistance(branches, rootId, leafId).getDistance();
20+
return shortestDistance;
21+
}
22+
23+
/**
24+
* BFS 알고리즘을 이용해 두 멤버 사이의 가장 짧은 거리를 계산합니다.
25+
* @param branches
26+
* @param startMemberId
27+
* @param endMemberId
28+
* @return 두 멤버 사이의 가장 짧은 거리
29+
*/
30+
31+
public static BranchResponseDTO.ShortestPathResult findShortestDistance(List<Branch> branches, Long startMemberId, Long endMemberId) {
32+
Map<Long, List<Long>> adjacencyList = new HashMap<>();
33+
Map<Long, Long> prev = new HashMap<>();
34+
Set<Long> visited = new HashSet<>();
35+
Queue<Long> queue = new LinkedList<>();
36+
37+
// 각 멤버 ID를 기준으로 연결된 Branch를 매핑
38+
for (Branch branch : branches) {
39+
adjacencyList.computeIfAbsent(branch.getRoot().getId(), k -> new ArrayList<>()).add(branch.getLeaf().getId());
40+
adjacencyList.computeIfAbsent(branch.getLeaf().getId(), k -> new ArrayList<>()).add(branch.getRoot().getId());
41+
}
42+
43+
queue.add(startMemberId);
44+
visited.add(startMemberId);
45+
prev.put(startMemberId, null); // 시작 노드의 선행자는 없음
46+
47+
while (!queue.isEmpty()) {
48+
Long current = queue.poll();
49+
if (current.equals(endMemberId)) {
50+
break; // 목표 노드에 도달
51+
}
52+
for (Long neighbor : adjacencyList.getOrDefault(current, Collections.emptyList())) {
53+
if (!visited.contains(neighbor)) {
54+
visited.add(neighbor);
55+
queue.add(neighbor);
56+
prev.put(neighbor, current);
57+
}
58+
}
59+
}
60+
61+
// 경로 복원 및 결과 생성
62+
List<Long> path = new ArrayList<>();
63+
Long current = endMemberId;
64+
while (current != null) {
65+
path.add(current);
66+
current = prev.get(current);
67+
}
68+
Collections.reverse(path); // 경로를 역순으로 뒤집어 정상 순서로 만듦
69+
70+
int distance = path.size() - 1; // 거리는 경로의 길이에서 1을 뺀 값
71+
return BranchMapper.toShortestPathResult(distance, path);
72+
}
73+
74+
/**
75+
* 특정 멤버와 가장 가까운 멤버(branchDegree = 1)의 수를 반환합니다.
76+
* @param memberId
77+
* @return
78+
*/
79+
public static Integer countClosestMembers(List<Branch> branches, Long memberId) {
80+
int count = 0;
81+
for (Branch branch : branches) {
82+
if (branch.getRoot().getId().equals(memberId) || branch.getLeaf().getId().equals(memberId)) {
83+
count++;
84+
}
85+
}
86+
return count;
87+
}
88+
}

src/main/java/treehouse/server/api/comment/business/CommentMapper.java

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
package treehouse.server.api.comment.business;
22

3-
import lombok.AccessLevel;
4-
import lombok.NoArgsConstructor;
5-
import lombok.RequiredArgsConstructor;
6-
import org.springframework.stereotype.Component;
73
import treehouse.server.api.comment.presentation.dto.CommentResponseDTO;
84
import treehouse.server.api.member.business.MemberMapper;
95
import treehouse.server.api.reaction.presentation.dto.ReactionResponseDTO;
10-
import treehouse.server.global.entity.User.User;
116
import treehouse.server.global.entity.comment.Comment;
127
import treehouse.server.global.entity.member.Member;
138
import treehouse.server.global.entity.post.Post;
149

1510
import java.util.List;
16-
import java.util.stream.Collectors;
1711

1812
public class CommentMapper {
1913

@@ -24,7 +18,7 @@ public static CommentResponseDTO.CommentInfoDto toCommentInfoDto(Comment comment
2418
.commentId(comment.getId())
2519
.context(comment.getContent())
2620
.reactionList(reactionList)
27-
.memberProfile(MemberMapper.toGetMemberProfile(comment.getWriter()))
21+
.memberProfile(MemberMapper.toGetWriterProfile(comment.getWriter()))
2822
.build();
2923

3024
}

src/main/java/treehouse/server/api/comment/presentation/dto/CommentResponseDTO.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public class CommentResponseDTO {
1818
@AllArgsConstructor
1919
public static class CommentInfoDto{
2020

21-
MemberResponseDTO.getMemberProfile memberProfile;
21+
MemberResponseDTO.getWriterProfile memberProfile;
2222
ReactionResponseDTO.getReactionList reactionList;
2323
Long commentId;
2424
String context;

src/main/java/treehouse/server/api/member/business/MemberMapper.java

+24-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
import lombok.RequiredArgsConstructor;
44
import org.springframework.stereotype.Component;
5+
import treehouse.server.api.branch.business.BranchUtil;
56
import treehouse.server.api.member.presentation.dto.MemberRequestDTO;
67
import treehouse.server.api.member.presentation.dto.MemberResponseDTO;
78
import treehouse.server.global.entity.User.User;
9+
import treehouse.server.global.entity.branch.Branch;
810
import treehouse.server.global.entity.member.Member;
911
import treehouse.server.global.entity.treeHouse.TreeHouse;
1012

1113
import java.util.ArrayList;
14+
import java.util.List;
1215

1316
@Component
1417
@RequiredArgsConstructor
@@ -35,12 +38,31 @@ public static MemberResponseDTO.registerMember toRegister(Member member) {
3538
.build();
3639
}
3740

38-
public static MemberResponseDTO.getMemberProfile toGetMemberProfile(Member member) {
39-
return MemberResponseDTO.getMemberProfile.builder()
41+
public static MemberResponseDTO.getWriterProfile toGetWriterProfile(Member member) {
42+
return MemberResponseDTO.getWriterProfile.builder()
4043
.memberId(member.getId())
4144
.memberName(member.getName())
4245
.memberProfileImageUrl(member.getProfileImageUrl())
4346
.memberBranch(3) // Branch 기능 개발 이후 변경 예정
4447
.build();
4548
}
49+
50+
public static MemberResponseDTO.getProfile toGetProfile(List<Branch> branches, Member member, Member targetMember) {
51+
return MemberResponseDTO.getProfile.builder()
52+
.memberId(member.getId())
53+
.memberName(member.getName())
54+
.userName(member.getUser().getName())
55+
.closestMemberCount(BranchUtil.countClosestMembers(branches, targetMember.getId())) // ClosestMember 기능 개발 이후 변경 예정
56+
.treehouseCount(member.getUser().getMemberList().size()) // TreehouseCount 기능 개발 이후 변경 예정
57+
.fromMe(BranchUtil.calculateBranchDegree(branches, member.getId(), targetMember.getId()))
58+
.profileImageUrl(member.getProfileImageUrl())
59+
.bio(member.getBio())
60+
.build();
61+
}
62+
63+
public static MemberResponseDTO.updateProfile toUpdateProfile(Member member) {
64+
return MemberResponseDTO.updateProfile.builder()
65+
.memberId(member.getId())
66+
.build();
67+
}
4668
}

src/main/java/treehouse/server/api/member/business/MemberService.java

+21
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@
44
import lombok.extern.slf4j.Slf4j;
55
import org.springframework.stereotype.Service;
66
import org.springframework.transaction.annotation.Transactional;
7+
import treehouse.server.api.branch.implementation.BranchQueryAdapter;
78
import treehouse.server.api.member.implementation.MemberCommandAdapter;
89
import treehouse.server.api.member.implementation.MemberQueryAdapter;
910
import treehouse.server.api.member.presentation.dto.MemberRequestDTO;
1011
import treehouse.server.api.member.presentation.dto.MemberResponseDTO;
1112
import treehouse.server.api.treehouse.implementation.TreehouseQueryAdapter;
1213
import treehouse.server.global.entity.User.User;
14+
import treehouse.server.global.entity.branch.Branch;
1315
import treehouse.server.global.entity.member.Member;
1416
import treehouse.server.global.entity.treeHouse.TreeHouse;
1517

18+
import java.util.List;
19+
1620
@Service
1721
@AllArgsConstructor
1822
@Slf4j
@@ -22,6 +26,7 @@ public class MemberService {
2226

2327
private final MemberCommandAdapter memberCommandAdapter;
2428
private final TreehouseQueryAdapter treehouseQueryAdapter;
29+
private final BranchQueryAdapter branchQueryAdapter;
2530

2631
/**
2732
* 트리하우스에 가입
@@ -40,4 +45,20 @@ public MemberResponseDTO.registerMember register(User user, MemberRequestDTO.reg
4045

4146
return MemberMapper.toRegister(savedMember);
4247
}
48+
49+
@Transactional(readOnly = true)
50+
public MemberResponseDTO.getProfile getMyProfile(User user, Long treehouseId){
51+
TreeHouse treeHouse = treehouseQueryAdapter.getTreehouseById(treehouseId);
52+
Member member = memberQueryAdapter.findByUserAndTreehouse(user, treeHouse);
53+
List<Branch> branches = branchQueryAdapter.findAllByTreeHouse(treeHouse); // 트리하우스 내 모든 브랜치 조회
54+
return MemberMapper.toGetProfile(branches, member, member);
55+
}
56+
57+
@Transactional
58+
public MemberResponseDTO.updateProfile updateProfile(User user, Long treehouseId, MemberRequestDTO.updateProfile request){
59+
TreeHouse treeHouse = treehouseQueryAdapter.getTreehouseById(treehouseId);
60+
Member member = memberQueryAdapter.findByUserAndTreehouse(user, treeHouse);
61+
member.updateMember(request.getMemberName(), request.getBio(), request.getProfileImageURL());
62+
return MemberMapper.toUpdateProfile(member);
63+
}
4364
}

src/main/java/treehouse/server/api/member/presentation/MemberApi.java

+21-6
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
import lombok.RequiredArgsConstructor;
77
import lombok.extern.slf4j.Slf4j;
88
import org.springframework.validation.annotation.Validated;
9-
import org.springframework.web.bind.annotation.PostMapping;
10-
import org.springframework.web.bind.annotation.RequestBody;
11-
import org.springframework.web.bind.annotation.RequestMapping;
12-
import org.springframework.web.bind.annotation.RestController;
9+
import org.springframework.web.bind.annotation.*;
1310
import treehouse.server.api.member.business.MemberService;
1411
import treehouse.server.api.member.presentation.dto.MemberRequestDTO;
1512
import treehouse.server.api.member.presentation.dto.MemberResponseDTO;
@@ -22,17 +19,35 @@
2219
@Slf4j
2320
@Validated
2421
@Tag(name = "Member API", description = "트리하우스 멤버 관련 API 입니다. 트리하우스 멤버 가입, 탈퇴 등의 API가 포함됩니다.")
25-
@RequestMapping("/members")
2622
public class MemberApi {
2723

2824
private final MemberService memberService;
2925

30-
@PostMapping("/register")
26+
@PostMapping("/members/register")
3127
@Operation(summary = "트리하우스 회원가입 \uD83D\uDD11✅", description = "트리하우스 멤버로 가입합니다.")
3228
public CommonResponse<MemberResponseDTO.registerMember> registerTreehouseMember(
3329
@RequestBody final MemberRequestDTO.registerMember request,
3430
@AuthMember @Parameter(hidden = true) User user
3531
){
3632
return CommonResponse.onSuccess(memberService.register(user, request));
3733
}
34+
35+
@GetMapping("/treehouses/{treehouseId}/profiles/myProfile")
36+
@Operation(summary = "내 프로필 조회 \uD83D\uDC64 ✅", description = "특정 트리하우스에서 내 프로필을 조회합니다.")
37+
public CommonResponse<MemberResponseDTO.getProfile> getMyProfile(
38+
@PathVariable final Long treehouseId,
39+
@AuthMember @Parameter(hidden = true) User user
40+
){
41+
return CommonResponse.onSuccess(memberService.getMyProfile(user, treehouseId));
42+
}
43+
44+
@PatchMapping("/treehouses/{treehouseId}/profiles/myProfile")
45+
@Operation(summary = "내 프로필 수정 \uD83D\uDC64 ✅", description = "특정 트리하우스에서 내 프로필을 수정합니다.")
46+
public CommonResponse<MemberResponseDTO.updateProfile> updateProfile(
47+
@PathVariable final Long treehouseId,
48+
@RequestBody final MemberRequestDTO.updateProfile request,
49+
@AuthMember @Parameter(hidden = true) User user
50+
){
51+
return CommonResponse.onSuccess(memberService.updateProfile(user, treehouseId, request));
52+
}
3853
}

src/main/java/treehouse/server/api/member/presentation/dto/MemberRequestDTO.java

+7
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,11 @@ public static class registerMember {
1212
private String bio;
1313
private String profileImageURL;
1414
}
15+
16+
@Getter
17+
public static class updateProfile {
18+
private String memberName;
19+
private String bio;
20+
private String profileImageURL;
21+
}
1522
}

0 commit comments

Comments
 (0)