Skip to content
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

feat : 다른 유저 정보 조회 API 추가 #158

Merged
merged 8 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public record GetCommentResponse(Long commentId,
String writerProfileImage,
String content,
String createdAt) {

public static GetCommentResponse toDTO(Comment comment) {
return GetCommentResponse.builder()
.commentId(comment.getId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,4 +167,12 @@ public ResponseEntity<Void> editStudyGroupVisibility(@AuthedUser User user,
studyGroupService.editStudyGroupVisibility(user, request);
return ResponseEntity.ok().build();
}

@GetMapping(value = "/{userId}/list")
@Operation(summary = "타 유저 그룹 목록 조회 API", description = "유저가 보이도록 설정해놓은 유저가 참여하고 있는 그룹 모두 조회")
public ResponseEntity<GetStudyGroupListsResponse> getOtherUserStudyGroupList(@AuthedUser User user,
@RequestParam @PathVariable Long userId) {
GetStudyGroupListsResponse response = studyGroupService.getOtherStudyGroupList(userId);
return ResponseEntity.ok().body(response);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.gamzabat.algohub.feature.group.studygroup.dto;

import java.time.LocalDate;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import java.time.LocalDate;

public record CreateGroupRequest(@Size(min = 1, max = 15, message = "스터디 이름은 1글자 이상 15글자 이하로 작성해야 합니다.") String name,
@NotNull(message = "스터디 시작 날짜는 필수 입력 입니다.") LocalDate startDate,
@NotNull(message = "스터디 종료 날짜는 필수 입력 입니다.") LocalDate endDate,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.gamzabat.algohub.feature.group.studygroup.dto;

import java.time.LocalDate;

import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

import java.time.LocalDate;

public record EditGroupRequest(@NotNull(message = "그룹 고유 아이디는 필수 입력 입니다.") Long id,
@Size(min = 1, max = 15, message = "스터디 이름은 1글자 이상 15글자 이하로 작성해야 합니다.") String name,
LocalDate startDate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import java.time.LocalDate;

import com.gamzabat.algohub.feature.group.studygroup.etc.RoleOfGroupMember;
import com.gamzabat.algohub.common.DateFormatUtil;
import com.gamzabat.algohub.feature.group.studygroup.etc.RoleOfGroupMember;

import lombok.Getter;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,18 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import com.gamzabat.algohub.feature.group.studygroup.domain.GroupMember;
import com.gamzabat.algohub.feature.group.studygroup.domain.StudyGroup;
import com.gamzabat.algohub.feature.group.studygroup.etc.RoleOfGroupMember;
import com.gamzabat.algohub.feature.group.studygroup.domain.GroupMember;
import com.gamzabat.algohub.feature.user.domain.User;

public interface GroupMemberRepository extends JpaRepository<GroupMember, Long> {
boolean existsByUserAndStudyGroup(User user, StudyGroup studyGroup);

Optional<GroupMember> findByUserAndStudyGroup(User user, StudyGroup studyGroup);

boolean existsByUserAndStudyGroupAndIsVisible(User user, StudyGroup studyGroup, Boolean isVisible);

List<GroupMember> findAllByStudyGroup(StudyGroup studyGroup);

@Query("SELECT COUNT(gm) FROM GroupMember gm WHERE gm.studyGroup.id = :studyGroupId")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,49 @@ public void editStudyGroupVisibility(User user, EditGroupVisibilityRequest reque
log.info("success to update group visibility ( userId : {} )", user.getId());
}

@Transactional(readOnly = true)
public GetStudyGroupListsResponse getOtherStudyGroupList(Long targetUserId) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 뭔가 내 그룹 목록 조회 메소드랑 중복이 많아서 조회 메소드를 하나로 빼서 재사용하는 리팩토링 할 수 있을 것 같은데..

User targetUser = userRepository.findById(targetUserId)
.orElseThrow(() -> new CannotFoundUserException(HttpStatus.NOT_FOUND.value(), "존재하지 않는 유저입니다."));
List<StudyGroup> groups = groupRepository.findAllByUser(targetUser);

List<GetStudyGroupResponse> bookmarked = bookmarkedStudyGroupRepository.findAllByUser(targetUser).stream()
.filter(group -> isVisible(group.getStudyGroup(), targetUser))
.map(bookmark -> getStudyGroupResponseDTO(targetUser, bookmark.getStudyGroup()))
.toList();

LocalDate today = LocalDate.now();

List<GetStudyGroupResponse> done = groups.stream()
.filter(group -> group.getEndDate() != null && group.getEndDate().isBefore(today) && isVisible(group,
targetUser))
.map(group -> getStudyGroupResponseDTO(targetUser, group))
.toList();

List<GetStudyGroupResponse> inProgress = groups.stream()
.filter(
group -> !(group.getStartDate() == null || group.getStartDate().isAfter(today))
&& !(group.getEndDate() == null || group.getEndDate().isBefore(today)) && isVisible(group,
targetUser))
.map(group -> getStudyGroupResponseDTO(targetUser, group))
.toList();

List<GetStudyGroupResponse> queued = groups.stream()
.filter(group -> group.getStartDate() != null && group.getStartDate().isAfter(today) && isVisible(group,
targetUser))
.map(group -> getStudyGroupResponseDTO(targetUser, group))
.toList();

GetStudyGroupListsResponse response = new GetStudyGroupListsResponse(bookmarked, done, inProgress, queued);

log.info("success to get study group list");
return response;
}

private boolean isVisible(StudyGroup group, User user) {
return groupMemberRepository.existsByUserAndStudyGroupAndIsVisible(user, group, true);
}

private void sendNewMemberNotification(StudyGroup studyGroup, GroupMember newMember) {
List<GroupMember> members = groupMemberRepository.findAllByStudyGroup(studyGroup)
.stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
Expand Down Expand Up @@ -127,4 +128,12 @@ public ResponseEntity<Void> checkNickname(@RequestParam String nickname) {
userService.checkNickname(nickname);
return ResponseEntity.ok().build();
}

@GetMapping(value = "/{userId}/info")
@Operation(summary = "타회원정보조회 API")
public ResponseEntity<UserInfoResponse> getOtherUserInfo(@AuthedUser User user,
@RequestParam @PathVariable Long userId) {
UserInfoResponse userInfo = userService.otherUserInfo(user, userId);
return ResponseEntity.ok().body(userInfo);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.gamzabat.algohub.enums.Role;
import com.gamzabat.algohub.exception.JwtRequestException;
import com.gamzabat.algohub.exception.UserValidationException;
import com.gamzabat.algohub.feature.group.studygroup.exception.CannotFoundUserException;
import com.gamzabat.algohub.feature.image.service.ImageService;
import com.gamzabat.algohub.feature.user.domain.User;
import com.gamzabat.algohub.feature.user.dto.DeleteUserRequest;
Expand Down Expand Up @@ -189,6 +190,16 @@ public void checkNickname(String nickname) {
log.info("success to check nickname validity");
}

@Transactional(readOnly = true)
public UserInfoResponse otherUserInfo(User user, Long targetUserId) {
User targetUser = userRepository.findById(targetUserId)
.orElseThrow(() -> new CannotFoundUserException(HttpStatus.NOT_FOUND.value(), "해당 유저는 존재하지 않습니다."));

return new UserInfoResponse(targetUser.getEmail(), targetUser.getNickname(), targetUser.getProfileImage(),
targetUser.getBjNickname(),
targetUser.getDescription());
}

private boolean isInvalidNicknameForm(String nickname) {
String regex = "[^a-zA-Z0-9가-힣ㄱ-ㅎㅏ-ㅣ]";
return nickname.length() < 3 || nickname.length() > 16 || Pattern.compile(regex).matcher(nickname).find();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
Expand Down Expand Up @@ -38,6 +39,7 @@
import com.gamzabat.algohub.enums.Role;
import com.gamzabat.algohub.exception.JwtRequestException;
import com.gamzabat.algohub.exception.UserValidationException;
import com.gamzabat.algohub.feature.group.studygroup.exception.CannotFoundUserException;
import com.gamzabat.algohub.feature.image.service.ImageService;
import com.gamzabat.algohub.feature.user.domain.User;
import com.gamzabat.algohub.feature.user.dto.DeleteUserRequest;
Expand Down Expand Up @@ -385,4 +387,43 @@ void checkNickname_3() {
.hasFieldOrPropertyWithValue("code", HttpStatus.CONFLICT.value())
.hasFieldOrPropertyWithValue("error", "이미 사용 중인 닉네임입니다.");
}

@Test
@DisplayName("타회원 정보 조회 성공")
void otherUserInfo_success() {
// given
User user2 = User.builder()
.email("otherUserEmail")
.nickname("otherUserNickname")
.bjNickname("otherUserBjNickname")
.profileImage("otherUserProfileImage")
.role(Role.USER)
.build();
// when
when(userRepository.findById(user2.getId())).thenReturn(Optional.of(user2));
UserInfoResponse response = userService.otherUserInfo(user, user2.getId());
// then
assertThat(response.getEmail()).isEqualTo("otherUserEmail");
assertThat(response.getNickname()).isEqualTo("otherUserNickname");
assertThat(response.getProfileImage()).isEqualTo("otherUserProfileImage");
assertThat(response.getBjNickname()).isEqualTo("otherUserBjNickname");
assertThat(response.getDescription()).isEqualTo("");
}

@Test
@DisplayName("타회원 정보 조회 실패")
void otherUserInfo_failed() {
// given
when(userRepository.findById(1L)).thenReturn(Optional.empty());

// then
assertThatThrownBy(() -> userService.otherUserInfo(user, 1L))
.isInstanceOf(CannotFoundUserException.class)
.satisfies(exception -> {
CannotFoundUserException ex = (CannotFoundUserException)exception;
assertThat(ex.getCode()).isEqualTo(HttpStatus.NOT_FOUND.value());
assertThat(ex.getError()).isEqualTo("해당 유저는 존재하지 않습니다.");
});
}

}
106 changes: 106 additions & 0 deletions src/test/java/com/gamzabat/algohub/service/StudyGroupServiceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -728,4 +728,110 @@ void editGroupVisibilityFailed_2() {
.hasFieldOrPropertyWithValue("code", HttpStatus.FORBIDDEN.value())
.hasFieldOrPropertyWithValue("error", "참여하지 않은 그룹입니다.");
}

@Test
@DisplayName("타 이용자 그룹 목록 조회")
void getOtherUserGroupList() {
// given
List<StudyGroup> groups = new ArrayList<>(30);
for (int i = 0; i < 10; i++) {
StudyGroup group = StudyGroup.builder()
.name("name" + i)
.startDate(LocalDate.now().minusDays(i + 30))
.endDate(LocalDate.now().minusDays(30))
.build();
groups.add(group);
when(groupMemberRepository.findByStudyGroupAndRole(group, RoleOfGroupMember.OWNER)).thenReturn(
ownerGroupmember);
when(groupMemberRepository.findByUserAndStudyGroup(user, group)).thenReturn(
Optional.ofNullable(groupMember1));
when(groupMemberRepository.existsByUserAndStudyGroupAndIsVisible(user, group, true)).thenReturn(true);
}
for (int i = 0; i < 10; i++) {
StudyGroup group = StudyGroup.builder()
.name("name" + i)
.startDate(LocalDate.now().minusDays(i))
.endDate(LocalDate.now().plusDays(i))
.build();
groups.add(group);
when(groupMemberRepository.findByStudyGroupAndRole(group, RoleOfGroupMember.OWNER)).thenReturn(
ownerGroupmember);
when(groupMemberRepository.findByUserAndStudyGroup(user, group)).thenReturn(
Optional.ofNullable(groupMember1));
when(groupMemberRepository.existsByUserAndStudyGroupAndIsVisible(user, group, true)).thenReturn(true);
}
for (int i = 0; i < 10; i++) {
StudyGroup group = StudyGroup.builder()
.name("name" + i)
.startDate(LocalDate.now().plusDays(30))
.endDate(LocalDate.now().plusDays(i + 30))
.build();
groups.add(group);
when(groupMemberRepository.findByStudyGroupAndRole(group, RoleOfGroupMember.OWNER)).thenReturn(
groupMember2);
when(groupMemberRepository.findByUserAndStudyGroup(user, group)).thenReturn(
Optional.ofNullable(groupMember1));
when(groupMemberRepository.existsByUserAndStudyGroupAndIsVisible(user, group, true)).thenReturn(true);
}
List<BookmarkedStudyGroup> bookmarks = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
bookmarks.add(BookmarkedStudyGroup.builder()
.studyGroup(groups.get(i))
.user(user)
.build());
when(bookmarkedStudyGroupRepository.existsByUserAndStudyGroup(user, groups.get(i))).thenReturn(true);
when(groupMemberRepository.existsByUserAndStudyGroupAndIsVisible(user, groups.get(i), true)).thenReturn(
true);
}
when(bookmarkedStudyGroupRepository.findAllByUser(user)).thenReturn(bookmarks);
when(studyGroupRepository.findAllByUser(user)).thenReturn(groups);
when(userRepository.findById(user.getId())).thenReturn(Optional.of(user));
when(studyGroupRepository.findAllByUser(user)).thenReturn(groups);
// when
GetStudyGroupListsResponse result = studyGroupService.getOtherStudyGroupList(user.getId());
// then
List<GetStudyGroupResponse> bookmarked = result.getBookmarked();
List<GetStudyGroupResponse> done = result.getDone();
List<GetStudyGroupResponse> inProgress = result.getInProgress();
List<GetStudyGroupResponse> queued = result.getQueued();
assertThat(bookmarked.size()).isEqualTo(10);
assertThat(done.size()).isEqualTo(10);
assertThat(inProgress.size()).isEqualTo(10);
assertThat(queued.size()).isEqualTo(10);
for (int i = 0; i < 10; i++) {
assertThat(done.get(i).name()).isEqualTo("name" + i);
assertThat(done.get(i).ownerNickname()).isEqualTo("nickname1");
assertThat(done.get(i).startDate()).isEqualTo(DateFormatUtil.formatDate(LocalDate.now().minusDays(i + 30)));
assertThat(done.get(i).endDate()).isEqualTo(DateFormatUtil.formatDate(LocalDate.now().minusDays(30)));
assertThat(done.get(i).isBookmarked()).isTrue();
assertThat(done.get(i).isOwner()).isTrue();
}
for (int i = 0; i < 10; i++) {
assertThat(inProgress.get(i).name()).isEqualTo("name" + i);
assertThat(inProgress.get(i).ownerNickname()).isEqualTo("nickname1");
assertThat(inProgress.get(i).startDate()).isEqualTo(
DateFormatUtil.formatDate(LocalDate.now().minusDays(i)));
assertThat(inProgress.get(i).endDate()).isEqualTo(DateFormatUtil.formatDate(LocalDate.now().plusDays(i)));
assertThat(inProgress.get(i).isBookmarked()).isFalse();
assertThat(inProgress.get(i).isOwner()).isTrue();
}
for (int i = 0; i < 10; i++) {
assertThat(queued.get(i).name()).isEqualTo("name" + i);
assertThat(queued.get(i).ownerNickname()).isEqualTo("nickname2");
assertThat(queued.get(i).startDate()).isEqualTo(DateFormatUtil.formatDate(LocalDate.now().plusDays(30)));
assertThat(queued.get(i).endDate()).isEqualTo(DateFormatUtil.formatDate(LocalDate.now().plusDays(i + 30)));
assertThat(queued.get(i).isBookmarked()).isFalse();
assertThat(queued.get(i).isOwner()).isFalse();
}
for (int i = 0; i < 10; i++) {
assertThat(bookmarked.get(i).name()).isEqualTo("name" + i);
assertThat(bookmarked.get(i).ownerNickname()).isEqualTo("nickname1");
assertThat(bookmarked.get(i).startDate()).isEqualTo(
DateFormatUtil.formatDate(LocalDate.now().minusDays(i + 30)));
assertThat(bookmarked.get(i).endDate()).isEqualTo(DateFormatUtil.formatDate(LocalDate.now().minusDays(30)));
assertThat(bookmarked.get(i).isBookmarked()).isTrue();
assertThat(bookmarked.get(i).isOwner()).isTrue();
}
}

}
Loading