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 추가 #144

Merged
merged 10 commits into from
Nov 5, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.gamzabat.algohub.feature.group.studygroup.dto.CheckSolvedProblemResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.CreateGroupRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.EditGroupRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.EditGroupVisibilityRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetGroupMemberResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetGroupResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetStudyGroupListsResponse;
Expand Down Expand Up @@ -156,4 +157,14 @@ public ResponseEntity<String> getGroupRole(@AuthedUser User user, @RequestParam
String response = studyGroupService.getRoleInGroup(user, groupId);
return ResponseEntity.ok().body(response);
}

@PatchMapping(value = "/visibility")
@Operation(summary = "스터디 그룹 공개 여부 수정 API")
public ResponseEntity<Void> editStudyGroupVisibility(@AuthedUser User user,
@Valid @RequestBody EditGroupVisibilityRequest request, Errors errors) {
if (errors.hasErrors())
throw new RequestException("스터디 그룹 공개 수정 요청이 올바르지 않습니다.", errors);
studyGroupService.editStudyGroupVisibility(user, request);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -34,16 +35,23 @@ public class GroupMember {
private LocalDate joinDate;
@Enumerated(EnumType.STRING)
private RoleOfGroupMember role;
@NotNull
private Boolean isVisible;

@Builder
public GroupMember(User user, StudyGroup studyGroup, LocalDate joinDate, RoleOfGroupMember role) {
this.user = user;
this.studyGroup = studyGroup;
this.joinDate = joinDate;
this.role = role;
this.isVisible = true;
}

public void updateRole(RoleOfGroupMember role) {
this.role = role;
}

public void updateVisibility(boolean isVisible) {
this.isVisible = isVisible;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.gamzabat.algohub.feature.group.studygroup.dto;

import jakarta.validation.constraints.NotNull;

public record EditGroupVisibilityRequest(@NotNull(message = "그룹 아이디는 필수 입력입니다.") Long groupId,
boolean isVisible) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ public record GetStudyGroupResponse(Long id,
String introduction,
String ownerNickname,
boolean isOwner,
boolean isBookmarked) {
public static GetStudyGroupResponse toDTO(StudyGroup group, User user, boolean isBookmarked, User owner) {
boolean isBookmarked,
boolean isVisible) {
public static GetStudyGroupResponse toDTO(StudyGroup group, User user, boolean isBookmarked, User owner,
boolean isVisible) {
return new GetStudyGroupResponse(
group.getId(),
group.getName(),
Expand All @@ -23,7 +25,8 @@ public static GetStudyGroupResponse toDTO(StudyGroup group, User user, boolean i
group.getIntroduction(),
owner.getNickname(),
owner.getId().equals(user.getId()),
isBookmarked
isBookmarked,
isVisible
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.gamzabat.algohub.feature.group.studygroup.dto.CheckSolvedProblemResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.CreateGroupRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.EditGroupRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.EditGroupVisibilityRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetGroupMemberResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetGroupResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetStudyGroupListsResponse;
Expand Down Expand Up @@ -185,30 +186,26 @@ public GetStudyGroupListsResponse getStudyGroupList(User user) {
List<StudyGroup> groups = groupRepository.findAllByUser(user);

List<GetStudyGroupResponse> bookmarked = bookmarkedStudyGroupRepository.findAllByUser(user).stream()
.map(bookmark -> GetStudyGroupResponse.toDTO(bookmark.getStudyGroup(), user, true,
getStudyGroupOwner(bookmark.getStudyGroup())))
.map(bookmark -> getStudyGroupResponseDTO(user, bookmark.getStudyGroup()))
.toList();

LocalDate today = LocalDate.now();

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

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

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

GetStudyGroupListsResponse response = new GetStudyGroupListsResponse(bookmarked, done, inProgress, queued);
Expand All @@ -217,6 +214,13 @@ public GetStudyGroupListsResponse getStudyGroupList(User user) {
return response;
}

private GetStudyGroupResponse getStudyGroupResponseDTO(User user, StudyGroup group) {
GroupMember member = groupMemberRepository.findByUserAndStudyGroup(user, group)
.orElseThrow(() -> new GroupMemberValidationException(HttpStatus.FORBIDDEN.value(), "참여하지 않은 스터디 그룹입니다."));
return GetStudyGroupResponse.toDTO(group, user, isBookmarked(user, group), getStudyGroupOwner(group),
member.getIsVisible());
}

private User getStudyGroupOwner(StudyGroup group) {
return groupMemberRepository.findByStudyGroupAndRole(group, RoleOfGroupMember.OWNER).getUser();
}
Expand Down Expand Up @@ -416,4 +420,16 @@ public String getRoleInGroup(User user, Long groupId) {

return member.getRole().getValue();
}

@Transactional
public void editStudyGroupVisibility(User user, EditGroupVisibilityRequest request) {
StudyGroup group = groupRepository.findById(request.groupId())
.orElseThrow(() -> new CannotFoundGroupException("존재하지 않는 그룹입니다."));

GroupMember member = groupMemberRepository.findByUserAndStudyGroup(user, group)
.orElseThrow(() -> new GroupMemberValidationException(HttpStatus.FORBIDDEN.value(), "참여하지 않은 그룹입니다."));

member.updateVisibility(request.isVisible());
log.info("success to update group visibility ( userId : {} )", user.getId());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import com.gamzabat.algohub.feature.group.studygroup.dto.CheckSolvedProblemResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.CreateGroupRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.EditGroupRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.EditGroupVisibilityRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetGroupMemberResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetStudyGroupListsResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetStudyGroupResponse;
Expand Down Expand Up @@ -215,29 +216,29 @@ void getStudyGroupList() throws Exception {
bookmarked.add(new GetStudyGroupResponse(
(long)i, "name" + i, "groupImage" + 1,
DateFormatUtil.formatDate(LocalDate.now()), DateFormatUtil.formatDate(LocalDate.now().plusDays(i)),
"introduction" + 1, "nickname", true, true
"introduction" + 1, "nickname", true, true, true
));
}

for (int i = 0; i < 10; i++) {
done.add(new GetStudyGroupResponse(
(long)i, "name" + i, "groupImage" + 1,
DateFormatUtil.formatDate(LocalDate.now()), DateFormatUtil.formatDate(LocalDate.now().plusDays(i)),
"introduction" + 1, "nickname", true, true
"introduction" + 1, "nickname", true, true, true
));
}
for (int i = 0; i < 10; i++) {
inProgress.add(new GetStudyGroupResponse(
(long)i, "name" + i, "groupImage" + 1,
DateFormatUtil.formatDate(LocalDate.now()), DateFormatUtil.formatDate(LocalDate.now().plusDays(i)),
"introduction" + 1, "nickname", true, true
"introduction" + 1, "nickname", true, true, true
));
}
for (int i = 0; i < 10; i++) {
queued.add(new GetStudyGroupResponse(
(long)i, "name" + i, "groupImage" + 1,
DateFormatUtil.formatDate(LocalDate.now()), DateFormatUtil.formatDate(LocalDate.now().plusDays(i)),
"introduction" + 1, "nickname", true, true
"introduction" + 1, "nickname", true, true, true
));
}
GetStudyGroupListsResponse response = new GetStudyGroupListsResponse(bookmarked, done, inProgress, queued);
Expand Down Expand Up @@ -813,4 +814,50 @@ void getRoleInGroupFailed_2() throws Exception {
.andExpect(jsonPath("$.error").value("참여하지 않은 그룹입니다."));
verify(studyGroupService, times(1)).getRoleInGroup(user, groupId);
}

@Test
@DisplayName("스터디 그룹 공개 여부 수정 성공")
void editGroupVisibility() throws Exception {
// given
EditGroupVisibilityRequest request = new EditGroupVisibilityRequest(groupId, false);
// when, then
mockMvc.perform(patch("/api/group/visibility")
.header("Authorization", token)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isOk());
verify(studyGroupService, times(1)).editStudyGroupVisibility(user, request);
}

@Test
@DisplayName("스터디 그룹 공개 여부 수정 실패 : 존재하지 않는 스터디 그룹")
void editGroupVisibilityFailed_1() throws Exception {
// given
EditGroupVisibilityRequest request = new EditGroupVisibilityRequest(groupId, false);
doThrow(new CannotFoundGroupException("존재하지 않는 그룹입니다.")).when(studyGroupService)
.editStudyGroupVisibility(user, request);
// when, then
mockMvc.perform(patch("/api/group/visibility")
.header("Authorization", token)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isNotFound())
.andExpect(jsonPath("$.error").value("존재하지 않는 그룹입니다."));
verify(studyGroupService, times(1)).editStudyGroupVisibility(user, request);
}

@Test
@DisplayName("스터디 그룹 공개 여부 수정 실패 : 참여하지 않은 그룹")
void editGroupVisibilityFailed_2() throws Exception {
// given
EditGroupVisibilityRequest request = new EditGroupVisibilityRequest(groupId, false);
doThrow(new GroupMemberValidationException(HttpStatus.FORBIDDEN.value(), "참여하지 않은 그룹입니다.")).when(
studyGroupService)
.editStudyGroupVisibility(user, request);
// when, then
mockMvc.perform(patch("/api/group/visibility")
.header("Authorization", token)
.content(objectMapper.writeValueAsString(request)))
.andExpect(status().isForbidden())
.andExpect(jsonPath("$.error").value("참여하지 않은 그룹입니다."));
verify(studyGroupService, times(1)).editStudyGroupVisibility(user, request);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import com.gamzabat.algohub.feature.group.studygroup.dto.BookmarkStatus;
import com.gamzabat.algohub.feature.group.studygroup.dto.CreateGroupRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.EditGroupRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.EditGroupVisibilityRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetGroupMemberResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetStudyGroupListsResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.GetStudyGroupResponse;
Expand Down Expand Up @@ -321,6 +322,8 @@ void getGroupList() {
groups.add(group);
when(groupMemberRepository.findByStudyGroupAndRole(group, RoleOfGroupMember.OWNER)).thenReturn(
ownerGroupmember);
when(groupMemberRepository.findByUserAndStudyGroup(user, group)).thenReturn(
Optional.ofNullable(groupMember1));
}
for (int i = 0; i < 10; i++) {
StudyGroup group = StudyGroup.builder()
Expand All @@ -331,6 +334,8 @@ void getGroupList() {
groups.add(group);
when(groupMemberRepository.findByStudyGroupAndRole(group, RoleOfGroupMember.OWNER)).thenReturn(
ownerGroupmember);
when(groupMemberRepository.findByUserAndStudyGroup(user, group)).thenReturn(
Optional.ofNullable(groupMember1));
}
for (int i = 0; i < 10; i++) {
StudyGroup group = StudyGroup.builder()
Expand All @@ -341,6 +346,8 @@ void getGroupList() {
groups.add(group);
when(groupMemberRepository.findByStudyGroupAndRole(group, RoleOfGroupMember.OWNER)).thenReturn(
groupMember2);
when(groupMemberRepository.findByUserAndStudyGroup(user, group)).thenReturn(
Optional.ofNullable(groupMember1));
}
List<BookmarkedStudyGroup> bookmarks = new ArrayList<>(10);
for (int i = 0; i < 10; i++) {
Expand Down Expand Up @@ -662,4 +669,42 @@ void getRoleInGroupFailed_2() {
.hasFieldOrPropertyWithValue("error", "참여하지 않은 그룹입니다.");
}

@Test
@DisplayName("스터디 그룹 공개 여부 수정 성공")
void editGroupVisibility() {
// given
EditGroupVisibilityRequest request = new EditGroupVisibilityRequest(groupId, false);
when(studyGroupRepository.findById(groupId)).thenReturn(Optional.of(group));
when(groupMemberRepository.findByUserAndStudyGroup(user, group)).thenReturn(Optional.of(groupMember1));
// when
studyGroupService.editStudyGroupVisibility(user, request);
// then
assertThat(groupMember1.getIsVisible()).isFalse();
}

@Test
@DisplayName("스터디 그룹 공개 여부 수정 실패 : 존재하지 않는 그룹")
void editGroupVisibilityFailed_1() {
// given
EditGroupVisibilityRequest request = new EditGroupVisibilityRequest(groupId, false);
when(studyGroupRepository.findById(groupId)).thenReturn(Optional.empty());
// when, then
assertThatThrownBy(() -> studyGroupService.editStudyGroupVisibility(user, request))
.isInstanceOf(CannotFoundGroupException.class)
.hasFieldOrPropertyWithValue("errors", "존재하지 않는 그룹입니다.");
}

@Test
@DisplayName("스터디 그룹 공개 여부 수정 실패 : 참여하지 않은 그룹")
void editGroupVisibilityFailed_2() {
// given
EditGroupVisibilityRequest request = new EditGroupVisibilityRequest(groupId, false);
when(studyGroupRepository.findById(groupId)).thenReturn(Optional.of(group));
when(groupMemberRepository.findByUserAndStudyGroup(user, group)).thenReturn(Optional.empty());
// when, then
assertThatThrownBy(() -> studyGroupService.editStudyGroupVisibility(user, request))
.isInstanceOf(GroupMemberValidationException.class)
.hasFieldOrPropertyWithValue("code", HttpStatus.FORBIDDEN.value())
.hasFieldOrPropertyWithValue("error", "참여하지 않은 그룹입니다.");
}
}
Loading