Skip to content

Commit 3dfcee4

Browse files
authored
Merge pull request #12 from WhosInRoom/feat/#10-myPage
[Feat[ 마이페이지 기능
2 parents 93e7379 + aaabe66 commit 3dfcee4

12 files changed

Lines changed: 363 additions & 17 deletions

File tree

src/main/java/com/WhoIsRoom/WhoIs_Server/domain/auth/controller/AuthController.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,4 @@ public BaseResponse<Void> findPassword(@RequestBody MailRequest request) {
5555
userService.sendNewPassword(request);
5656
return BaseResponse.ok(null);
5757
}
58-
59-
@PatchMapping("/password")
60-
public BaseResponse<Void> updatePassword(@CurrentUserId Long userId,
61-
@RequestBody PasswordRequest request) {
62-
userService.updateMyPassword(userId, request);
63-
return BaseResponse.ok(null);
64-
}
6558
}

src/main/java/com/WhoIsRoom/WhoIs_Server/domain/auth/filter/JwtAuthenticationFilter.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
4040

4141
// 인증을 안해도 되니 토큰이 필요없는 URL들 (에러: 로그인이 필요합니다)
4242
public final static List<String> PASS_URIS = Arrays.asList(
43-
"/api/users/signup",
44-
"/api/auth/**"
43+
"/api/users/signup", "/api/auth/**"
4544
);
4645

4746
private static final AntPathMatcher ANT = new AntPathMatcher();
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.WhoIsRoom.WhoIs_Server.domain.club.repository;
2+
3+
import com.WhoIsRoom.WhoIs_Server.domain.club.model.Club;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
public interface ClubRepository extends JpaRepository<Club, Long> {
7+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.WhoIsRoom.WhoIs_Server.domain.member.repository;
2+
3+
import com.WhoIsRoom.WhoIs_Server.domain.member.model.Member;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.data.jpa.repository.Modifying;
6+
import org.springframework.data.jpa.repository.Query;
7+
import org.springframework.data.repository.query.Param;
8+
9+
import java.util.Collection;
10+
import java.util.List;
11+
12+
public interface MemberRepository extends JpaRepository<Member, Long> {
13+
List<Member> findByUserId(Long userId);
14+
// 현재 유저가 속한 clubId 목록만 빠르게 가져오기
15+
@Query("select m.club.id from Member m where m.user.id = :userId")
16+
List<Long> findClubIdsByUserId(@Param("userId") Long userId);
17+
18+
@Modifying(clearAutomatically = true, flushAutomatically = true)
19+
@Query("delete from Member m where m.user.id = :userId and m.club.id in :clubIds")
20+
void deleteByUserIdAndClubIdIn(@Param("userId") Long userId, @Param("clubIds") Collection<Long> clubIds);
21+
}

src/main/java/com/WhoIsRoom/WhoIs_Server/domain/user/controller/UserController.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
package com.WhoIsRoom.WhoIs_Server.domain.user.controller;
22

3+
import com.WhoIsRoom.WhoIs_Server.domain.auth.dto.request.PasswordRequest;
4+
import com.WhoIsRoom.WhoIs_Server.domain.user.dto.request.MyPageUpdateRequest;
35
import com.WhoIsRoom.WhoIs_Server.domain.user.dto.request.SignupRequest;
6+
import com.WhoIsRoom.WhoIs_Server.domain.user.dto.response.MyPageResponse;
47
import com.WhoIsRoom.WhoIs_Server.domain.user.service.UserService;
8+
import com.WhoIsRoom.WhoIs_Server.global.common.resolver.CurrentUserId;
59
import com.WhoIsRoom.WhoIs_Server.global.common.response.BaseResponse;
610
import lombok.RequiredArgsConstructor;
711
import lombok.extern.slf4j.Slf4j;
8-
import org.springframework.web.bind.annotation.PostMapping;
9-
import org.springframework.web.bind.annotation.RequestBody;
10-
import org.springframework.web.bind.annotation.RequestMapping;
11-
import org.springframework.web.bind.annotation.RestController;
12+
import org.springframework.web.bind.annotation.*;
1213

1314
@Slf4j
1415
@RestController
@@ -23,4 +24,24 @@ public BaseResponse<Void> signUp(@RequestBody SignupRequest request) {
2324
userService.signUp(request);
2425
return BaseResponse.ok(null);
2526
}
27+
28+
@GetMapping("/myPage")
29+
public BaseResponse<MyPageResponse> getMyPage(@CurrentUserId Long userId) {
30+
MyPageResponse response = userService.getMyPage(userId);
31+
return BaseResponse.ok(response);
32+
}
33+
34+
@PatchMapping("/myPage/update")
35+
public BaseResponse<MyPageResponse> updateMyPage(@CurrentUserId Long userId,
36+
@RequestBody MyPageUpdateRequest request) {
37+
MyPageResponse response = userService.updateMyPage(userId, request);
38+
return BaseResponse.ok(response);
39+
}
40+
41+
@PatchMapping("/password")
42+
public BaseResponse<Void> updatePassword(@CurrentUserId Long userId,
43+
@RequestBody PasswordRequest request) {
44+
userService.updateMyPassword(userId, request);
45+
return BaseResponse.ok(null);
46+
}
2647
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.WhoIsRoom.WhoIs_Server.domain.user.dto.request;
2+
3+
import lombok.*;
4+
5+
import java.util.List;
6+
7+
@Getter
8+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
9+
@Builder
10+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
11+
public class MyPageUpdateRequest {
12+
String nickName;
13+
List<Long> clubList;
14+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.WhoIsRoom.WhoIs_Server.domain.user.dto.response;
2+
3+
import com.WhoIsRoom.WhoIs_Server.domain.club.model.Club;
4+
import lombok.Builder;
5+
import lombok.Getter;
6+
7+
@Getter
8+
@Builder
9+
public class ClubResponse {
10+
private Long id;
11+
private String name;
12+
13+
public static ClubResponse from(Club club) {
14+
return ClubResponse.builder()
15+
.id(club.getId())
16+
.name(club.getName())
17+
.build();
18+
}
19+
20+
21+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.WhoIsRoom.WhoIs_Server.domain.user.dto.response;
2+
3+
import com.WhoIsRoom.WhoIs_Server.domain.member.model.Member;
4+
import lombok.Builder;
5+
import lombok.Getter;
6+
7+
import java.util.List;
8+
9+
@Getter
10+
@Builder
11+
public class MyPageResponse {
12+
private String nickName;
13+
private List<ClubResponse> clubList;
14+
15+
public static MyPageResponse from(String nickname, List<Member> memberList) {
16+
17+
List<ClubResponse> clubList = memberList.stream()
18+
.map(Member::getClub)
19+
.distinct()
20+
.map(ClubResponse::from)
21+
.toList();
22+
23+
return MyPageResponse.builder()
24+
.nickName(nickname)
25+
.clubList(clubList)
26+
.build();
27+
}
28+
}

src/main/java/com/WhoIsRoom/WhoIs_Server/domain/user/service/UserService.java

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@
33
import com.WhoIsRoom.WhoIs_Server.domain.auth.dto.request.MailRequest;
44
import com.WhoIsRoom.WhoIs_Server.domain.auth.dto.request.PasswordRequest;
55
import com.WhoIsRoom.WhoIs_Server.domain.auth.service.MailService;
6+
import com.WhoIsRoom.WhoIs_Server.domain.club.model.Club;
7+
import com.WhoIsRoom.WhoIs_Server.domain.club.repository.ClubRepository;
8+
import com.WhoIsRoom.WhoIs_Server.domain.member.model.Member;
9+
import com.WhoIsRoom.WhoIs_Server.domain.member.repository.MemberRepository;
10+
import com.WhoIsRoom.WhoIs_Server.domain.user.dto.request.MyPageUpdateRequest;
611
import com.WhoIsRoom.WhoIs_Server.domain.user.dto.request.SignupRequest;
12+
import com.WhoIsRoom.WhoIs_Server.domain.user.dto.response.MyPageResponse;
713
import com.WhoIsRoom.WhoIs_Server.domain.user.model.Role;
814
import com.WhoIsRoom.WhoIs_Server.domain.user.model.User;
915
import com.WhoIsRoom.WhoIs_Server.domain.user.repository.UserRepository;
@@ -15,13 +21,21 @@
1521
import org.springframework.stereotype.Service;
1622
import org.springframework.transaction.annotation.Transactional;
1723

24+
import java.util.LinkedHashSet;
25+
import java.util.List;
26+
import java.util.Objects;
27+
import java.util.Set;
28+
import java.util.stream.Collectors;
29+
1830
@Slf4j
1931
@Service
2032
@RequiredArgsConstructor
2133
public class UserService {
2234
private final UserRepository userRepository;
2335
private final PasswordEncoder passwordEncoder;
2436
private final MailService mailService;
37+
private final MemberRepository memberRepository;
38+
private final ClubRepository clubRepository;
2539

2640
@Transactional
2741
public void signUp(SignupRequest request) {
@@ -62,4 +76,89 @@ public void updateMyPassword(Long userId, PasswordRequest request) {
6276
}
6377
user.setPassword(passwordEncoder.encode(request.getNewPassword()));
6478
}
79+
80+
@Transactional(readOnly = true)
81+
public MyPageResponse getMyPage(Long userId) {
82+
User user = userRepository.findById(userId)
83+
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
84+
85+
List<Member> memberList = memberRepository.findByUserId(userId);
86+
return MyPageResponse.from(user.getNickName(), memberList);
87+
}
88+
89+
@Transactional
90+
public MyPageResponse updateMyPage(Long userId, MyPageUpdateRequest request) {
91+
92+
User user = userRepository.findById(userId)
93+
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND));
94+
95+
updateUserNickName(user, request.getNickName());
96+
97+
updateUserClubs(user, request.getClubList());
98+
99+
List<Member> updatedMemberList = memberRepository.findByUserId(userId);
100+
return MyPageResponse.from(user.getNickName(), updatedMemberList);
101+
}
102+
103+
private void updateUserNickName(User user, String newNickName) {
104+
105+
// 변경 사항이 없으면 아무것도 하지 않음 (최적화)
106+
if (user.getNickName().equals(newNickName)) {
107+
return;
108+
}
109+
110+
// 닉네임 중복 검사 (자기 자신은 제외되므로 안전함)
111+
if (userRepository.existsByNickName(newNickName)) {
112+
throw new BusinessException(ErrorCode.USER_DUPLICATE_NICKNAME);
113+
}
114+
115+
user.setNickName(newNickName);
116+
}
117+
118+
private void updateUserClubs(User user, List<Long> newClubIdList) {
119+
120+
// null이면 빈 리스트로 간주 => 모두 탈퇴 처리
121+
Set<Long> requested = newClubIdList == null ? Set.of()
122+
: newClubIdList.stream()
123+
.filter(Objects::nonNull)
124+
.collect(Collectors.toCollection(LinkedHashSet::new)); // 순서 유지 필요시
125+
126+
Long userId = user.getId();
127+
128+
// 현재 가입된 clubId 목록
129+
Set<Long> current = new LinkedHashSet<>(memberRepository.findClubIdsByUserId(userId));
130+
131+
// 계산: 추가/삭제 집합
132+
Set<Long> toAdd = new LinkedHashSet<>(requested);
133+
toAdd.removeAll(current);
134+
135+
Set<Long> toRemove = new LinkedHashSet<>(current);
136+
toRemove.removeAll(requested);
137+
138+
// 삭제 먼저 (없으면 no-op)
139+
if (!toRemove.isEmpty()) {
140+
memberRepository.deleteByUserIdAndClubIdIn(userId, toRemove);
141+
}
142+
143+
// 추가할 Club의 존재성 검증
144+
if (!toAdd.isEmpty()) {
145+
List<Club> clubs = clubRepository.findAllById(toAdd);
146+
147+
if (clubs.size() != toAdd.size()) {
148+
// 어떤 ID는 존재X
149+
throw new BusinessException(ErrorCode.CLUB_NOT_FOUND);
150+
}
151+
152+
// Member 엔티티 생성
153+
List<Member> newMembers = clubs.stream()
154+
.map(club -> Member.builder()
155+
.user(user)
156+
.club(club)
157+
.build())
158+
.toList();
159+
160+
// 저장 (유니크 제약 (user_id, club_id) 있어도 toAdd는 중복이 아님)
161+
memberRepository.saveAll(newMembers);
162+
}
163+
}
65164
}

src/main/java/com/WhoIsRoom/WhoIs_Server/global/common/resolver/CurrentUserIdArgumentResolver.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.WhoIsRoom.WhoIs_Server.global.common.resolver;
22

3+
import com.WhoIsRoom.WhoIs_Server.domain.auth.model.UserPrincipal;
34
import com.WhoIsRoom.WhoIs_Server.domain.user.repository.UserRepository;
45
import com.WhoIsRoom.WhoIs_Server.global.common.exception.BusinessException;
56
import com.WhoIsRoom.WhoIs_Server.global.common.response.ErrorCode;
@@ -29,9 +30,7 @@ public Object resolveArgument(MethodParameter parameter,
2930
NativeWebRequest webRequest,
3031
WebDataBinderFactory binderFactory) throws Exception {
3132

32-
String email = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
33-
return userRepository.findByEmail(email)
34-
.orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND))
35-
.getId();
33+
UserPrincipal principal = (UserPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
34+
return principal.getUserId();
3635
}
3736
}

0 commit comments

Comments
 (0)