Skip to content
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

개인적으로 JoinRequestController가 따로 쪼개져도 괜찮을 것 같다고 생각합니다!
사유는.. service 분리 요청 이유와 같습니다.. 너무 커지는 이유..

Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
import com.gamzabat.algohub.feature.group.studygroup.dto.GroupRoleResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.UpdateBookmarkResponse;
import com.gamzabat.algohub.feature.group.studygroup.dto.UpdateGroupMemberRoleRequest;
import com.gamzabat.algohub.feature.group.studygroup.dto.UpdateJoinRequestStatusRequest;
import com.gamzabat.algohub.feature.group.studygroup.exception.JoinRequestException;
import com.gamzabat.algohub.feature.group.studygroup.service.JoinRequestService;
import com.gamzabat.algohub.feature.group.studygroup.service.StudyGroupService;
import com.gamzabat.algohub.feature.user.domain.User;

Expand All @@ -51,6 +54,7 @@
@Tag(name = "그룹 API", description = "스터디 그룹 관련 API")
public class StudyGroupController {
private final StudyGroupService studyGroupService;
private final JoinRequestService joinRequestService;

@PostMapping(value = "/groups", consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "그룹 생성 API")
Expand Down Expand Up @@ -208,34 +212,31 @@ public ResponseEntity<Page<GetGroupResponse>> getSearchedGroupList(@RequestParam
return ResponseEntity.ok().body(responses);
}

@PostMapping(value = "/{groupId}/join-request")
@PostMapping(value = "/groups/{groupId}/join-request")
@Operation(summary = "그룹 가입 요청 API", description = "스터디 그룹에 가입 요청을 보내는 API")
public ResponseEntity<Void> joinRequest(@AuthedUser User user, @PathVariable Long groupId) {
studyGroupService.joinRequest(user, groupId);
joinRequestService.joinRequest(user, groupId);
return ResponseEntity.ok().build();
}

@GetMapping(value = "/{groupId}/join-request")
@GetMapping(value = "/groups/{groupId}/join-request")
@Operation(summary = "그룹 가입 요청 목록 조회 API", description = "스터디 그룹 가입 요청 목록을 조회하는 API")
public ResponseEntity<List<JoinRequest>> getAllJoinRequests(@AuthedUser User user, @PathVariable Long groupId) {
List<JoinRequest> response = studyGroupService.getAllJoinRequests(user, groupId);
List<JoinRequest> response = joinRequestService.getAllJoinRequests(user, groupId);

return ResponseEntity.ok().body(response);
}

@PostMapping(value = "/{groupId}/{requestId}/approve")
@Operation(summary = "그룹 가입 요청 승인 API", description = "스터디 그룹 가입 요청을 승인하는 API")
public ResponseEntity<Void> approveRequest(@AuthedUser User user, @PathVariable Long requestId,
@PathVariable Long groupId) {
studyGroupService.approveJoinRequest(user, requestId, groupId);
return ResponseEntity.ok().build();
}

@PostMapping(value = "/{groupId}/{requestId}/reject")
@Operation(summary = "그룹 가입 요청 거절 API", description = "스터디 그룹 가입 요청을 거절하는 API")
public ResponseEntity<Void> rejectRequest(@AuthedUser User user, @PathVariable Long requestId,
@PathVariable Long groupId) {
studyGroupService.rejectJoinRequest(user, requestId, groupId);
@PostMapping(value = "/groups/{groupId}/join-request/{requestId}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

이제보니 groupId는 받을 필요 없을 것 같아요.. ㅎㅎ JoinRequest에 이미 group이 담겨있어서..!

@Operation(summary = "그룹 가입 요청 승인 / 거절", description = "스터디 그룹 가입 요청을 승인 / 거절하는 API")
public ResponseEntity<Void> updateRequest(
@AuthedUser User user,
@PathVariable Long requestId,
@PathVariable Long groupId,
@RequestBody @Valid UpdateJoinRequestStatusRequest request, Errors errors) {
if (errors.hasErrors())
throw new JoinRequestException("가입 요청이 올바르지 않습니다.");
joinRequestService.updateJoinRequest(user, requestId, groupId, request);
return ResponseEntity.ok().build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import lombok.Getter;
import lombok.Setter;
import lombok.NoArgsConstructor;

@Entity
@Setter
@Getter
@NoArgsConstructor
public class JoinRequest {
@Id
@GeneratedValue
Expand All @@ -33,23 +33,18 @@ public class JoinRequest {
@Enumerated(EnumType.STRING)
private JoinRequestStatus status = JoinRequestStatus.PENDING;

public void approve() {
if (status != JoinRequestStatus.PENDING)
return;
status = JoinRequestStatus.APPROVE;
public JoinRequest(StudyGroup group, User requester) {
this.group = group;
this.requester = requester;
}

public void reject() {
if (status != JoinRequestStatus.PENDING)
public void updateStatus(JoinRequestStatus status) {
if (status != JoinRequestStatus.PENDING) {
return;
status = JoinRequestStatus.REJECT;
}
this.status = status;
}

public void cancel() {
if (status != JoinRequestStatus.PENDING)
return;
status = JoinRequestStatus.CANCEL;
}
}


This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.gamzabat.algohub.feature.group.studygroup.dto;

import com.gamzabat.algohub.enums.JoinRequestStatus;

import jakarta.validation.constraints.NotNull;

public record UpdateJoinRequestStatusRequest(@NotNull(message = "status 는 필수입니다.") JoinRequestStatus status) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.gamzabat.algohub.feature.group.studygroup.service;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.gamzabat.algohub.enums.JoinRequestStatus;
import com.gamzabat.algohub.exception.StudyGroupValidationException;
import com.gamzabat.algohub.feature.group.studygroup.domain.GroupMember;
import com.gamzabat.algohub.feature.group.studygroup.domain.JoinRequest;
import com.gamzabat.algohub.feature.group.studygroup.domain.StudyGroup;
import com.gamzabat.algohub.feature.group.studygroup.dto.UpdateJoinRequestStatusRequest;
import com.gamzabat.algohub.feature.group.studygroup.etc.RoleOfGroupMember;
import com.gamzabat.algohub.feature.group.studygroup.exception.GroupMemberValidationException;
import com.gamzabat.algohub.feature.group.studygroup.exception.JoinRequestException;
import com.gamzabat.algohub.feature.group.studygroup.repository.GroupMemberRepository;
import com.gamzabat.algohub.feature.group.studygroup.repository.JoinRequestRepository;
import com.gamzabat.algohub.feature.group.studygroup.repository.StudyGroupRepository;
import com.gamzabat.algohub.feature.user.domain.User;
import com.gamzabat.algohub.feature.user.repository.UserRepository;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
@RequiredArgsConstructor
public class JoinRequestService {
private final StudyGroupRepository studyGroupRepository;
private final GroupMemberRepository groupMemberRepository;
private final UserRepository userRepository;
private final JoinRequestRepository joinRequestRepository;

@Transactional
public void joinRequest(User user, Long groupId) {
StudyGroup studyGroup = studyGroupRepository.findById(groupId)
.orElseThrow(() -> new StudyGroupValidationException(HttpStatus.NOT_FOUND.value(), "존재하지 않는 그룹 입니다."));
if (groupMemberRepository.existsByUserAndStudyGroup(user, studyGroup)) {
throw new GroupMemberValidationException(HttpStatus.BAD_REQUEST.value(), "이미 가입한 그룹입니다");
}
if (joinRequestRepository.existsByGroup_IdAndRequester_Id(groupId, user.getId())) {
throw new JoinRequestException("이미 요청한 그룹입니다.");
}

JoinRequest request = new JoinRequest(studyGroup, user);
joinRequestRepository.save(request);
log.info("success to join request group = {}", groupId);
}

@Transactional(readOnly = true)
public List<JoinRequest> getAllJoinRequests(User user, Long groupId) {
StudyGroup studyGroup = studyGroupRepository.findById(groupId)
.orElseThrow(() -> new StudyGroupValidationException(HttpStatus.NOT_FOUND.value(), "존재하지 않는 그룹 입니다."));
Optional<GroupMember> groupMember = groupMemberRepository.findByUserAndStudyGroup(user, studyGroup);
if (groupMember.isPresent() && RoleOfGroupMember.isParticipant(groupMember.get()) || groupMember.isEmpty()) {
throw new JoinRequestException("요청 목록을 조회할 권한이 없습니다.");
}
return joinRequestRepository.findAllByGroup_Id(groupId);
}

@Transactional
public void updateJoinRequest(User user, Long requestId, Long groupId, UpdateJoinRequestStatusRequest request) {
JoinRequest joinRequest = joinRequestRepository.findById(requestId)
.orElseThrow(() -> new JoinRequestException("해당 요청이 존재하지 않습니다"));
StudyGroup studyGroup = studyGroupRepository.findById(groupId)
.orElseThrow(() -> new StudyGroupValidationException(HttpStatus.NOT_FOUND.value(), "존재하지 않는 그룹입니다."));
GroupMember groupMember = groupMemberRepository.findByUserAndStudyGroup(user, studyGroup)
.orElseThrow(() -> new GroupMemberValidationException(HttpStatus.NOT_FOUND.value(), "해당 그룹의 멤버가 아닙니다."));
if (RoleOfGroupMember.isParticipant(groupMember)) {
throw new JoinRequestException("승인 권한이 없습니다.");
}
if (request.status() == JoinRequestStatus.APPROVE) {
joinRequest.updateStatus(request.status());
GroupMember newGroupMember = GroupMember.builder()
.user(joinRequest.getRequester())
.studyGroup(studyGroup)
.joinDate(LocalDate.now())
.role(RoleOfGroupMember.PARTICIPANT)
.build();
groupMemberRepository.save(newGroupMember);
joinRequestRepository.delete(joinRequest);
Comment on lines +82 to +104
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

가입 후 처리에 누락된 부분이 있습니다!

가입 처리 되면 NotificationSettingRanking도 함께 데이터가 insert 되어야 합니다.
그룹 참여 API 메서드 내용 참고하고 추가해주면 좋을 것 같습니다!

} else if (request.status() == JoinRequestStatus.REJECT) {
joinRequestRepository.delete(joinRequest);
}
log.info("success to approve/reject for join request group = {}", groupId);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import com.gamzabat.algohub.feature.group.ranking.repository.RankingRepository;
import com.gamzabat.algohub.feature.group.studygroup.domain.BookmarkedStudyGroup;
import com.gamzabat.algohub.feature.group.studygroup.domain.GroupMember;
import com.gamzabat.algohub.feature.group.studygroup.domain.JoinRequest;
import com.gamzabat.algohub.feature.group.studygroup.domain.StudyGroup;
import com.gamzabat.algohub.feature.group.studygroup.dto.BookmarkStatus;
import com.gamzabat.algohub.feature.group.studygroup.dto.CheckSolvedProblemResponse;
Expand All @@ -51,7 +50,6 @@
import com.gamzabat.algohub.feature.group.studygroup.exception.CannotFoundProblemException;
import com.gamzabat.algohub.feature.group.studygroup.exception.CannotFoundUserException;
import com.gamzabat.algohub.feature.group.studygroup.exception.GroupMemberValidationException;
import com.gamzabat.algohub.feature.group.studygroup.exception.JoinRequestException;
import com.gamzabat.algohub.feature.group.studygroup.repository.BookmarkedStudyGroupRepository;
import com.gamzabat.algohub.feature.group.studygroup.repository.GroupMemberRepository;
import com.gamzabat.algohub.feature.group.studygroup.repository.JoinRequestRepository;
Expand Down Expand Up @@ -659,71 +657,4 @@ public Page<GetGroupResponse> getSearchedStudyGroupList(String searchPattern, Pa
));
}

@Transactional
public void joinRequest(User user, Long groupId) {
StudyGroup studyGroup = groupRepository.findById(groupId)
.orElseThrow(() -> new StudyGroupValidationException(HttpStatus.NOT_FOUND.value(), "존재하지 않는 그룹 입니다."));
if (groupMemberRepository.existsByUserAndStudyGroup(user, studyGroup)) {
throw new GroupMemberValidationException(HttpStatus.BAD_REQUEST.value(), "이미 가입한 그룹입니다");
}
if (joinRequestRepository.existsByGroup_IdAndRequester_Id(groupId, user.getId())) {
throw new JoinRequestException("이미 요청한 그룹입니다.");
}

JoinRequest request = new JoinRequest();
request.setRequester(user);
request.setGroup(studyGroup);
joinRequestRepository.save(request);
log.info("success to join request group = {}", groupId);
}

@Transactional(readOnly = true)
public List<JoinRequest> getAllJoinRequests(User user, Long groupId) {
StudyGroup studyGroup = groupRepository.findById(groupId)
.orElseThrow(() -> new StudyGroupValidationException(HttpStatus.NOT_FOUND.value(), "존재하지 않는 그룹 입니다."));
Optional<GroupMember> groupMember = groupMemberRepository.findByUserAndStudyGroup(user, studyGroup);
if (groupMember.isPresent() && RoleOfGroupMember.isParticipant(groupMember.get()) || groupMember.isEmpty()) {
throw new JoinRequestException("요청 목록을 조회할 권한이 없습니다.");
}
return joinRequestRepository.findAllByGroup_Id(groupId);
}

@Transactional
public void approveJoinRequest(User user, Long requestId, Long groupId) {
JoinRequest joinRequest = joinRequestRepository.findById(requestId)
.orElseThrow(() -> new JoinRequestException("해당 요청이 존재하지 않습니다"));
StudyGroup studyGroup = studyGroupRepository.findById(groupId)
.orElseThrow(() -> new StudyGroupValidationException(HttpStatus.NOT_FOUND.value(), "존재하지 않는 그룹입니다."));
GroupMember groupMember = groupMemberRepository.findByUserAndStudyGroup(user, studyGroup)
.orElseThrow(() -> new GroupMemberValidationException(HttpStatus.NOT_FOUND.value(), "해당 그룹의 멤버가 아닙니다."));
if (RoleOfGroupMember.isParticipant(groupMember)) {
throw new JoinRequestException("승인 권한이 없습니다.");
}
joinRequest.approve();
GroupMember newGroupMember = GroupMember.builder()
.user(joinRequest.getRequester())
.studyGroup(studyGroup)
.joinDate(LocalDate.now())
.role(RoleOfGroupMember.PARTICIPANT)
.build();
groupMemberRepository.save(newGroupMember);
joinRequestRepository.delete(joinRequest);
log.info("success to approve join request group = {}", groupId);
}

@Transactional
public void rejectJoinRequest(User user, Long requestId, Long groupId) {
JoinRequest joinRequest = joinRequestRepository.findById(requestId)
.orElseThrow(() -> new JoinRequestException("해당 요청이 존재하지 않습니다"));
StudyGroup studyGroup = studyGroupRepository.findById(groupId)
.orElseThrow(() -> new StudyGroupValidationException(HttpStatus.NOT_FOUND.value(), "존재하지 않는 그룹입니다."));
GroupMember groupMember = groupMemberRepository.findByUserAndStudyGroup(user, studyGroup)
.orElseThrow(() -> new GroupMemberValidationException(HttpStatus.NOT_FOUND.value(), "해당 그룹의 멤버가 아닙니다."));
if (RoleOfGroupMember.isParticipant(groupMember)) {
throw new JoinRequestException("승인 권한이 없습니다.");
}
joinRequestRepository.delete(joinRequest);
log.info("success to reject join request group = {} and delete request = {} ", groupId, requestId);

}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approve와 reject를 하나로 묶으려면 isApproved 필드를 하나 더 받아서 처리하면 되지 않을까 싶네요! reject를 만들지 말지 프론트랑 결정해서 하면 될거같아요

Loading