From a0eb5e6139d6dae6991cdba6de70d67ff5480f42 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Thu, 8 Aug 2024 00:27:54 +0900 Subject: [PATCH 01/14] =?UTF-8?q?feat:=20StudyHistory=EC=97=90=20=EB=A0=88?= =?UTF-8?q?=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20=EB=A7=81=ED=81=AC=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/gdschongik/gdsc/domain/study/domain/StudyHistory.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistory.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistory.java index a77ad9dd3..dc0ad4b5a 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistory.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistory.java @@ -33,6 +33,8 @@ public class StudyHistory extends BaseEntity { @JoinColumn(name = "study_id") private Study study; + private String repositoryLink; + @Builder(access = AccessLevel.PRIVATE) private StudyHistory(Member mentee, Study study) { this.mentee = mentee; From c34d2ddb5233979ae1a5e65511bd35dd6fec08d1 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Thu, 8 Aug 2024 00:38:06 +0900 Subject: [PATCH 02/14] =?UTF-8?q?feat:=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=9E=85=EB=A0=A5=20api=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/study/api/StudyController.java | 12 +++++++ .../study/application/StudyService.java | 35 +++++++++++++++++++ .../AssignmentHistoryCustomRepository.java | 9 +++++ ...AssignmentHistoryCustomRepositoryImpl.java | 28 +++++++++++++++ .../dao/AssignmentHistoryRepository.java | 7 ++++ .../domain/study/domain/StudyHistory.java | 7 ++++ .../study/domain/StudyHistoryValidator.java | 6 ++++ .../dto/request/RepositoryUpdateRequest.java | 5 +++ .../common/constant/GithubConstant.java | 8 +++++ .../gdsc/global/exception/ErrorCode.java | 6 +++- .../infra/client/github/GithubClient.java | 12 +++++++ 11 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepository.java create mode 100644 src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java create mode 100644 src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryRepository.java create mode 100644 src/main/java/com/gdschongik/gdsc/domain/study/dto/request/RepositoryUpdateRequest.java create mode 100644 src/main/java/com/gdschongik/gdsc/global/common/constant/GithubConstant.java diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyController.java b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyController.java index 79e46d71d..8c85d05f8 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyController.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyController.java @@ -1,16 +1,20 @@ package com.gdschongik.gdsc.domain.study.api; import com.gdschongik.gdsc.domain.study.application.StudyService; +import com.gdschongik.gdsc.domain.study.dto.request.RepositoryUpdateRequest; import com.gdschongik.gdsc.domain.study.dto.response.StudyResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; 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; import org.springframework.web.bind.annotation.RestController; @@ -42,4 +46,12 @@ public ResponseEntity cancelStudyApply(@PathVariable Long studyId) { studyService.cancelStudyApply(studyId); return ResponseEntity.noContent().build(); } + + @Operation(summary = "레포지토리 입력", description = "레포지토리를 입력합니다. 이미 제출한 과제가 있다면 수정할 수 없습니다.") + @PatchMapping("/{studyId}/repository") + public ResponseEntity updateRepository( + @PathVariable Long studyId, @Valid @RequestBody RepositoryUpdateRequest request) { + studyService.updateRepository(studyId, request); + return ResponseEntity.ok().build(); + } } diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java index c0ed98955..d2d418771 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java @@ -1,16 +1,20 @@ package com.gdschongik.gdsc.domain.study.application; +import static com.gdschongik.gdsc.global.common.constant.GithubConstant.*; import static com.gdschongik.gdsc.global.exception.ErrorCode.*; import com.gdschongik.gdsc.domain.member.domain.Member; +import com.gdschongik.gdsc.domain.study.dao.AssignmentHistoryRepository; import com.gdschongik.gdsc.domain.study.dao.StudyHistoryRepository; import com.gdschongik.gdsc.domain.study.dao.StudyRepository; import com.gdschongik.gdsc.domain.study.domain.Study; import com.gdschongik.gdsc.domain.study.domain.StudyHistory; import com.gdschongik.gdsc.domain.study.domain.StudyHistoryValidator; +import com.gdschongik.gdsc.domain.study.dto.request.RepositoryUpdateRequest; import com.gdschongik.gdsc.domain.study.dto.response.StudyResponse; import com.gdschongik.gdsc.global.exception.CustomException; import com.gdschongik.gdsc.global.util.MemberUtil; +import com.gdschongik.gdsc.infra.client.github.GithubClient; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -24,8 +28,10 @@ public class StudyService { private final MemberUtil memberUtil; + private final GithubClient githubClient; private final StudyRepository studyRepository; private final StudyHistoryRepository studyHistoryRepository; + private final AssignmentHistoryRepository assignmentHistoryRepository; private final StudyHistoryValidator studyHistoryValidator; public List getAllApplicableStudies() { @@ -64,4 +70,33 @@ public void cancelStudyApply(Long studyId) { log.info("[StudyService] 스터디 수강신청 취소: studyId={}, memberId={}", study.getId(), currentMember.getId()); } + + @Transactional + public void updateRepository(Long studyId, RepositoryUpdateRequest request) { + Member currentMember = memberUtil.getCurrentMember(); + Study study = studyRepository.findById(studyId).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND)); + + StudyHistory studyHistory = studyHistoryRepository + .findByMenteeAndStudy(currentMember, study) + .orElseThrow(() -> new CustomException(STUDY_HISTORY_NOT_FOUND)); + + boolean isRepositoryUpdatable = assignmentHistoryRepository.existsSubmittedAssignment(currentMember, study); + studyHistoryValidator.validateUpdateRepository(isRepositoryUpdatable); + validateRepositoryLink(request.repositoryLink()); + + studyHistory.updateRepositoryLink(request.repositoryLink()); + studyHistoryRepository.save(studyHistory); + + log.info("[StudentStudyService] 레포지토리 입력: studyHistoryId={}", studyHistory.getId()); + } + + private void validateRepositoryLink(String repositoryLink) { + String ownerRepo = getOwnerRepo(repositoryLink); + githubClient.getRepositoryLink(ownerRepo); + } + + private String getOwnerRepo(String repositoryLink) { + int startIndex = repositoryLink.indexOf(GITHUB_DOMAIN) + GITHUB_DOMAIN.length(); + return repositoryLink.substring(startIndex); + } } diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepository.java b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepository.java new file mode 100644 index 000000000..98ce39ce9 --- /dev/null +++ b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepository.java @@ -0,0 +1,9 @@ +package com.gdschongik.gdsc.domain.study.dao; + +import com.gdschongik.gdsc.domain.member.domain.Member; +import com.gdschongik.gdsc.domain.study.domain.Study; + +public interface AssignmentHistoryCustomRepository { + + boolean existsSubmittedAssignment(Member member, Study study); +} diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java new file mode 100644 index 000000000..a00fc7cd5 --- /dev/null +++ b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java @@ -0,0 +1,28 @@ +package com.gdschongik.gdsc.domain.study.dao; + +import static com.gdschongik.gdsc.domain.study.domain.AssignmentSubmissionStatus.*; +import static com.gdschongik.gdsc.domain.study.domain.QAssignmentHistory.*; + +import com.gdschongik.gdsc.domain.member.domain.Member; +import com.gdschongik.gdsc.domain.study.domain.Study; +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class AssignmentHistoryCustomRepositoryImpl implements AssignmentHistoryCustomRepository { + + private final JPAQueryFactory queryFactory; + + @Override + public boolean existsSubmittedAssignment(Member member, Study study) { + Integer fetchOne = queryFactory + .selectOne() + .from(assignmentHistory) + .where( + assignmentHistory.studyDetail.study.eq(study), + assignmentHistory.submissionStatus.in(FAILURE, SUCCESS)) + .fetchFirst(); + + return fetchOne != null; + } +} diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryRepository.java b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryRepository.java new file mode 100644 index 000000000..89ed0c714 --- /dev/null +++ b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryRepository.java @@ -0,0 +1,7 @@ +package com.gdschongik.gdsc.domain.study.dao; + +import com.gdschongik.gdsc.domain.study.domain.AssignmentHistory; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface AssignmentHistoryRepository + extends JpaRepository, AssignmentHistoryCustomRepository {} diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistory.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistory.java index dc0ad4b5a..52689f528 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistory.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistory.java @@ -45,6 +45,13 @@ public static StudyHistory create(Member mentee, Study study) { return StudyHistory.builder().mentee(mentee).study(study).build(); } + /** + * 레포지토리 링크를 업데이트합니다. + */ + public void updateRepositoryLink(String repositoryLink) { + this.repositoryLink = repositoryLink; + } + // 데이터 전달 로직 public boolean isStudyOngoing() { return study.isStudyOngoing(); diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java index aed358292..3f0c09f62 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java @@ -37,4 +37,10 @@ public void validateCancelStudyApply(Study study) { throw new CustomException(STUDY_NOT_CANCELABLE_APPLICATION_PERIOD); } } + + public void validateUpdateRepository(boolean isRepositoryUpdatable) { + if (!isRepositoryUpdatable) { + throw new CustomException(STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE); + } + } } diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/dto/request/RepositoryUpdateRequest.java b/src/main/java/com/gdschongik/gdsc/domain/study/dto/request/RepositoryUpdateRequest.java new file mode 100644 index 000000000..7f311f37b --- /dev/null +++ b/src/main/java/com/gdschongik/gdsc/domain/study/dto/request/RepositoryUpdateRequest.java @@ -0,0 +1,5 @@ +package com.gdschongik.gdsc.domain.study.dto.request; + +import jakarta.validation.constraints.NotBlank; + +public record RepositoryUpdateRequest(@NotBlank String repositoryLink) {} diff --git a/src/main/java/com/gdschongik/gdsc/global/common/constant/GithubConstant.java b/src/main/java/com/gdschongik/gdsc/global/common/constant/GithubConstant.java new file mode 100644 index 000000000..fc593abc6 --- /dev/null +++ b/src/main/java/com/gdschongik/gdsc/global/common/constant/GithubConstant.java @@ -0,0 +1,8 @@ +package com.gdschongik.gdsc.global.common.constant; + +public class GithubConstant { + + public static final String GITHUB_DOMAIN = "github.com/"; + + private GithubConstant() {} +} diff --git a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java index 17686780c..cceed6623 100644 --- a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java +++ b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java @@ -117,6 +117,7 @@ public enum ErrorCode { STUDY_HISTORY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 수강 기록입니다."), STUDY_HISTORY_DUPLICATE(HttpStatus.CONFLICT, "이미 해당 스터디를 신청했습니다."), STUDY_HISTORY_ONGOING_ALREADY_EXISTS(HttpStatus.CONFLICT, "이미 진행중인 스터디가 있습니다."), + STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE(HttpStatus.CONFLICT, "이미 제출한 과제가 있으므로 레포지토리를 수정할 수 없습니다."), // Order ORDER_NOT_FOUND(HttpStatus.NOT_FOUND, "주문이 존재하지 않습니다."), @@ -142,7 +143,10 @@ public enum ErrorCode { // Assignment ASSIGNMENT_CAN_NOT_BE_UPDATED(HttpStatus.CONFLICT, "휴강인 과제는 수정할 수 없습니다."), - ASSIGNMENT_DEADLINE_INVALID(HttpStatus.CONFLICT, "과제 마감 기한이 현재보다 빠릅니다."); + ASSIGNMENT_DEADLINE_INVALID(HttpStatus.CONFLICT, "과제 마감 기한이 현재보다 빠릅니다."), + + // Github + GITHUB_REPOSITORY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 레포지토리입니다."); private final HttpStatus status; private final String message; diff --git a/src/main/java/com/gdschongik/gdsc/infra/client/github/GithubClient.java b/src/main/java/com/gdschongik/gdsc/infra/client/github/GithubClient.java index e3235dfb7..5004a5db7 100644 --- a/src/main/java/com/gdschongik/gdsc/infra/client/github/GithubClient.java +++ b/src/main/java/com/gdschongik/gdsc/infra/client/github/GithubClient.java @@ -1,6 +1,10 @@ package com.gdschongik.gdsc.infra.client.github; +import com.gdschongik.gdsc.global.exception.CustomException; +import com.gdschongik.gdsc.global.exception.ErrorCode; +import java.io.IOException; import lombok.RequiredArgsConstructor; +import org.kohsuke.github.GHRepository; import org.kohsuke.github.GitHub; import org.springframework.stereotype.Component; @@ -9,4 +13,12 @@ public class GithubClient { private final GitHub github; + + public GHRepository getRepositoryLink(String ownerRepo) { + try { + return github.getRepository(ownerRepo); + } catch (IOException e) { + throw new CustomException(ErrorCode.GITHUB_REPOSITORY_NOT_FOUND); + } + } } From fc70a79ecc95a52e567eb453105fc5a01df7b6f3 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Thu, 8 Aug 2024 00:41:24 +0900 Subject: [PATCH 03/14] =?UTF-8?q?test:=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=9E=85=EB=A0=A5=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../study/domain/StudyHistoryValidatorTest.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java index 4631ab5da..545ae78ba 100644 --- a/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java +++ b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java @@ -96,4 +96,19 @@ class 스터디_수강신청_취소시 { .hasMessage(STUDY_NOT_CANCELABLE_APPLICATION_PERIOD.getMessage()); } } + + @Nested + class 레포지토리_입력시 { + + @Test + void 이미_제출한_과제가_있다면_실패한다() { + // given + boolean isRepositoryUpdatable = false; + + // when & then + assertThatThrownBy(() -> studyHistoryValidator.validateUpdateRepository(isRepositoryUpdatable)) + .isInstanceOf(CustomException.class) + .hasMessage(STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE.getMessage()); + } + } } From 513ddbc98e6ec0238e2c65a741b3e3d578dc7794 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Thu, 8 Aug 2024 00:44:24 +0900 Subject: [PATCH 04/14] =?UTF-8?q?rename:=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdsc/domain/study/application/StudyService.java | 4 ++-- .../gdsc/domain/study/domain/StudyHistoryValidator.java | 5 +++-- .../gdsc/domain/study/domain/StudyHistoryValidatorTest.java | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java index d2d418771..6473d0806 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java @@ -80,8 +80,8 @@ public void updateRepository(Long studyId, RepositoryUpdateRequest request) { .findByMenteeAndStudy(currentMember, study) .orElseThrow(() -> new CustomException(STUDY_HISTORY_NOT_FOUND)); - boolean isRepositoryUpdatable = assignmentHistoryRepository.existsSubmittedAssignment(currentMember, study); - studyHistoryValidator.validateUpdateRepository(isRepositoryUpdatable); + boolean isAnyAssignmentSubmitted = assignmentHistoryRepository.existsSubmittedAssignment(currentMember, study); + studyHistoryValidator.validateUpdateRepository(isAnyAssignmentSubmitted); validateRepositoryLink(request.repositoryLink()); studyHistory.updateRepositoryLink(request.repositoryLink()); diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java index 3f0c09f62..e742d43e0 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java @@ -38,8 +38,9 @@ public void validateCancelStudyApply(Study study) { } } - public void validateUpdateRepository(boolean isRepositoryUpdatable) { - if (!isRepositoryUpdatable) { + public void validateUpdateRepository(boolean isAnyAssignmentSubmitted) { + // 이미 제출한 과제가 있는 경우 + if (isAnyAssignmentSubmitted) { throw new CustomException(STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE); } } diff --git a/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java index 545ae78ba..447966d88 100644 --- a/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java +++ b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java @@ -103,10 +103,10 @@ class 레포지토리_입력시 { @Test void 이미_제출한_과제가_있다면_실패한다() { // given - boolean isRepositoryUpdatable = false; + boolean isAnyAssignmentSubmitted = true; // when & then - assertThatThrownBy(() -> studyHistoryValidator.validateUpdateRepository(isRepositoryUpdatable)) + assertThatThrownBy(() -> studyHistoryValidator.validateUpdateRepository(isAnyAssignmentSubmitted)) .isInstanceOf(CustomException.class) .hasMessage(STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE.getMessage()); } From 2aced6fadbbf9ce7da2d936798c566e2cbb7c599 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Thu, 8 Aug 2024 00:55:39 +0900 Subject: [PATCH 05/14] =?UTF-8?q?rename:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdschongik/gdsc/domain/study/application/StudyService.java | 2 +- .../com/gdschongik/gdsc/infra/client/github/GithubClient.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java index 6473d0806..481506381 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java @@ -92,7 +92,7 @@ public void updateRepository(Long studyId, RepositoryUpdateRequest request) { private void validateRepositoryLink(String repositoryLink) { String ownerRepo = getOwnerRepo(repositoryLink); - githubClient.getRepositoryLink(ownerRepo); + githubClient.getRepository(ownerRepo); } private String getOwnerRepo(String repositoryLink) { diff --git a/src/main/java/com/gdschongik/gdsc/infra/client/github/GithubClient.java b/src/main/java/com/gdschongik/gdsc/infra/client/github/GithubClient.java index 5004a5db7..6085c2c03 100644 --- a/src/main/java/com/gdschongik/gdsc/infra/client/github/GithubClient.java +++ b/src/main/java/com/gdschongik/gdsc/infra/client/github/GithubClient.java @@ -14,7 +14,7 @@ public class GithubClient { private final GitHub github; - public GHRepository getRepositoryLink(String ownerRepo) { + public GHRepository getRepository(String ownerRepo) { try { return github.getRepository(ownerRepo); } catch (IOException e) { From c8be71d77bac1331c22c7d44f1a0a4f9f6435d98 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Thu, 8 Aug 2024 00:58:59 +0900 Subject: [PATCH 06/14] =?UTF-8?q?rename:=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdschongik/gdsc/domain/study/application/StudyService.java | 3 ++- .../domain/study/dao/AssignmentHistoryCustomRepository.java | 2 +- .../study/dao/AssignmentHistoryCustomRepositoryImpl.java | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java index 481506381..553ce5d84 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java @@ -80,7 +80,8 @@ public void updateRepository(Long studyId, RepositoryUpdateRequest request) { .findByMenteeAndStudy(currentMember, study) .orElseThrow(() -> new CustomException(STUDY_HISTORY_NOT_FOUND)); - boolean isAnyAssignmentSubmitted = assignmentHistoryRepository.existsSubmittedAssignment(currentMember, study); + boolean isAnyAssignmentSubmitted = + assignmentHistoryRepository.existsSubmittedAssignmentByMemberAndStudy(currentMember, study); studyHistoryValidator.validateUpdateRepository(isAnyAssignmentSubmitted); validateRepositoryLink(request.repositoryLink()); diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepository.java b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepository.java index 98ce39ce9..89766c38a 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepository.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepository.java @@ -5,5 +5,5 @@ public interface AssignmentHistoryCustomRepository { - boolean existsSubmittedAssignment(Member member, Study study); + boolean existsSubmittedAssignmentByMemberAndStudy(Member member, Study study); } diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java index a00fc7cd5..2f93dd00e 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java @@ -14,7 +14,7 @@ public class AssignmentHistoryCustomRepositoryImpl implements AssignmentHistoryC private final JPAQueryFactory queryFactory; @Override - public boolean existsSubmittedAssignment(Member member, Study study) { + public boolean existsSubmittedAssignmentByMemberAndStudy(Member member, Study study) { Integer fetchOne = queryFactory .selectOne() .from(assignmentHistory) From dc1361e5c97225033cf9e51dec4e308b2cdc6c77 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Thu, 8 Aug 2024 01:02:28 +0900 Subject: [PATCH 07/14] =?UTF-8?q?refactor:=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=A1=B0=EA=B1=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AssignmentHistoryCustomRepositoryImpl.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java index 2f93dd00e..c212e0f50 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/dao/AssignmentHistoryCustomRepositoryImpl.java @@ -5,6 +5,7 @@ import com.gdschongik.gdsc.domain.member.domain.Member; import com.gdschongik.gdsc.domain.study.domain.Study; +import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; @@ -18,11 +19,21 @@ public boolean existsSubmittedAssignmentByMemberAndStudy(Member member, Study st Integer fetchOne = queryFactory .selectOne() .from(assignmentHistory) - .where( - assignmentHistory.studyDetail.study.eq(study), - assignmentHistory.submissionStatus.in(FAILURE, SUCCESS)) + .where(eqMember(member), eqStudy(study), isSubmitted()) .fetchFirst(); return fetchOne != null; } + + private BooleanExpression eqMember(Member member) { + return member == null ? null : assignmentHistory.member.eq(member); + } + + private BooleanExpression eqStudy(Study study) { + return study == null ? null : assignmentHistory.studyDetail.study.eq(study); + } + + private BooleanExpression isSubmitted() { + return assignmentHistory.submissionStatus.in(FAILURE, SUCCESS); + } } From 501f0057c07ae6514d0acd58b115d4d7bcadc9c1 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 9 Aug 2024 00:11:03 +0900 Subject: [PATCH 08/14] =?UTF-8?q?fix:=20=EC=97=94=EB=93=9C=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/StudentStudyHistoryController.java | 31 +++++++++++++++++++ .../domain/study/api/StudyController.java | 12 ------- 2 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java new file mode 100644 index 000000000..d0bddc58f --- /dev/null +++ b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java @@ -0,0 +1,31 @@ +package com.gdschongik.gdsc.domain.study.api; + +import com.gdschongik.gdsc.domain.study.application.StudyHistoryService; +import com.gdschongik.gdsc.domain.study.dto.request.RepositoryUpdateRequest; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "Student Study History", description = "사용자 스터디 수강 이력 API입니다.") +@RestController +@RequestMapping("/study-history") +@RequiredArgsConstructor +public class StudentStudyHistoryController { + + private final StudyHistoryService studyHistoryService; + + @Operation(summary = "레포지토리 입력", description = "레포지토리를 입력합니다. 이미 제출한 과제가 있다면 수정할 수 없습니다.") + @PutMapping("/{studyHistoryId}/repository") + public ResponseEntity updateRepository( + @PathVariable Long studyHistoryId, @Valid @RequestBody RepositoryUpdateRequest request) { + studyHistoryService.updateRepository(studyHistoryId, request); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyController.java b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyController.java index 8c85d05f8..79e46d71d 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyController.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudyController.java @@ -1,20 +1,16 @@ package com.gdschongik.gdsc.domain.study.api; import com.gdschongik.gdsc.domain.study.application.StudyService; -import com.gdschongik.gdsc.domain.study.dto.request.RepositoryUpdateRequest; import com.gdschongik.gdsc.domain.study.dto.response.StudyResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; 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; import org.springframework.web.bind.annotation.RestController; @@ -46,12 +42,4 @@ public ResponseEntity cancelStudyApply(@PathVariable Long studyId) { studyService.cancelStudyApply(studyId); return ResponseEntity.noContent().build(); } - - @Operation(summary = "레포지토리 입력", description = "레포지토리를 입력합니다. 이미 제출한 과제가 있다면 수정할 수 없습니다.") - @PatchMapping("/{studyId}/repository") - public ResponseEntity updateRepository( - @PathVariable Long studyId, @Valid @RequestBody RepositoryUpdateRequest request) { - studyService.updateRepository(studyId, request); - return ResponseEntity.ok().build(); - } } From 0e7a6c3812983dd58f8712faaa098ba97e04a3cb Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 9 Aug 2024 00:11:19 +0900 Subject: [PATCH 09/14] =?UTF-8?q?fix:=20=EC=88=98=EA=B0=95=20=EC=9D=B4?= =?UTF-8?q?=EB=A0=A5=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/StudyHistoryService.java | 60 +++++++++++++++++++ .../study/application/StudyService.java | 35 ----------- 2 files changed, 60 insertions(+), 35 deletions(-) create mode 100644 src/main/java/com/gdschongik/gdsc/domain/study/application/StudyHistoryService.java diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyHistoryService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyHistoryService.java new file mode 100644 index 000000000..027c62ab5 --- /dev/null +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyHistoryService.java @@ -0,0 +1,60 @@ +package com.gdschongik.gdsc.domain.study.application; + +import static com.gdschongik.gdsc.global.common.constant.GithubConstant.*; +import static com.gdschongik.gdsc.global.exception.ErrorCode.*; + +import com.gdschongik.gdsc.domain.member.domain.Member; +import com.gdschongik.gdsc.domain.study.dao.AssignmentHistoryRepository; +import com.gdschongik.gdsc.domain.study.dao.StudyHistoryRepository; +import com.gdschongik.gdsc.domain.study.domain.Study; +import com.gdschongik.gdsc.domain.study.domain.StudyHistory; +import com.gdschongik.gdsc.domain.study.domain.StudyHistoryValidator; +import com.gdschongik.gdsc.domain.study.dto.request.RepositoryUpdateRequest; +import com.gdschongik.gdsc.global.exception.CustomException; +import com.gdschongik.gdsc.global.util.MemberUtil; +import com.gdschongik.gdsc.infra.client.github.GithubClient; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@Service +@RequiredArgsConstructor +public class StudyHistoryService { + + private final MemberUtil memberUtil; + private final GithubClient githubClient; + private final StudyHistoryRepository studyHistoryRepository; + private final AssignmentHistoryRepository assignmentHistoryRepository; + private final StudyHistoryValidator studyHistoryValidator; + + @Transactional + public void updateRepository(Long studyHistoryId, RepositoryUpdateRequest request) { + Member currentMember = memberUtil.getCurrentMember(); + StudyHistory studyHistory = studyHistoryRepository + .findById(studyHistoryId) + .orElseThrow(() -> new CustomException(STUDY_HISTORY_NOT_FOUND)); + Study study = studyHistory.getStudy(); + + boolean isAnyAssignmentSubmitted = + assignmentHistoryRepository.existsSubmittedAssignmentByMemberAndStudy(currentMember, study); + studyHistoryValidator.validateUpdateRepository(isAnyAssignmentSubmitted); + validateRepositoryLink(request.repositoryLink()); + + studyHistory.updateRepositoryLink(request.repositoryLink()); + studyHistoryRepository.save(studyHistory); + + log.info("[StudyHistoryService] 레포지토리 입력: studyHistoryId={}", studyHistory.getId()); + } + + private void validateRepositoryLink(String repositoryLink) { + String ownerRepo = getOwnerRepo(repositoryLink); + githubClient.getRepository(ownerRepo); + } + + private String getOwnerRepo(String repositoryLink) { + int startIndex = repositoryLink.indexOf(GITHUB_DOMAIN) + GITHUB_DOMAIN.length(); + return repositoryLink.substring(startIndex); + } +} diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java index 553ce5d84..3ec6a7870 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java @@ -4,17 +4,14 @@ import static com.gdschongik.gdsc.global.exception.ErrorCode.*; import com.gdschongik.gdsc.domain.member.domain.Member; -import com.gdschongik.gdsc.domain.study.dao.AssignmentHistoryRepository; import com.gdschongik.gdsc.domain.study.dao.StudyHistoryRepository; import com.gdschongik.gdsc.domain.study.dao.StudyRepository; import com.gdschongik.gdsc.domain.study.domain.Study; import com.gdschongik.gdsc.domain.study.domain.StudyHistory; import com.gdschongik.gdsc.domain.study.domain.StudyHistoryValidator; -import com.gdschongik.gdsc.domain.study.dto.request.RepositoryUpdateRequest; import com.gdschongik.gdsc.domain.study.dto.response.StudyResponse; import com.gdschongik.gdsc.global.exception.CustomException; import com.gdschongik.gdsc.global.util.MemberUtil; -import com.gdschongik.gdsc.infra.client.github.GithubClient; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -28,10 +25,8 @@ public class StudyService { private final MemberUtil memberUtil; - private final GithubClient githubClient; private final StudyRepository studyRepository; private final StudyHistoryRepository studyHistoryRepository; - private final AssignmentHistoryRepository assignmentHistoryRepository; private final StudyHistoryValidator studyHistoryValidator; public List getAllApplicableStudies() { @@ -70,34 +65,4 @@ public void cancelStudyApply(Long studyId) { log.info("[StudyService] 스터디 수강신청 취소: studyId={}, memberId={}", study.getId(), currentMember.getId()); } - - @Transactional - public void updateRepository(Long studyId, RepositoryUpdateRequest request) { - Member currentMember = memberUtil.getCurrentMember(); - Study study = studyRepository.findById(studyId).orElseThrow(() -> new CustomException(STUDY_NOT_FOUND)); - - StudyHistory studyHistory = studyHistoryRepository - .findByMenteeAndStudy(currentMember, study) - .orElseThrow(() -> new CustomException(STUDY_HISTORY_NOT_FOUND)); - - boolean isAnyAssignmentSubmitted = - assignmentHistoryRepository.existsSubmittedAssignmentByMemberAndStudy(currentMember, study); - studyHistoryValidator.validateUpdateRepository(isAnyAssignmentSubmitted); - validateRepositoryLink(request.repositoryLink()); - - studyHistory.updateRepositoryLink(request.repositoryLink()); - studyHistoryRepository.save(studyHistory); - - log.info("[StudentStudyService] 레포지토리 입력: studyHistoryId={}", studyHistory.getId()); - } - - private void validateRepositoryLink(String repositoryLink) { - String ownerRepo = getOwnerRepo(repositoryLink); - githubClient.getRepository(ownerRepo); - } - - private String getOwnerRepo(String repositoryLink) { - int startIndex = repositoryLink.indexOf(GITHUB_DOMAIN) + GITHUB_DOMAIN.length(); - return repositoryLink.substring(startIndex); - } } From 6310570d639b4f6aed7fdf29d18b26ef42d2d6c4 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 9 Aug 2024 00:18:58 +0900 Subject: [PATCH 10/14] =?UTF-8?q?remove:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20import=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdschongik/gdsc/domain/study/application/StudyService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java index 3ec6a7870..c0ed98955 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyService.java @@ -1,6 +1,5 @@ package com.gdschongik.gdsc.domain.study.application; -import static com.gdschongik.gdsc.global.common.constant.GithubConstant.*; import static com.gdschongik.gdsc.global.exception.ErrorCode.*; import com.gdschongik.gdsc.domain.member.domain.Member; From eb8cc081e0d810d147cce01ecc77201ba662ee70 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Fri, 9 Aug 2024 00:20:45 +0900 Subject: [PATCH 11/14] =?UTF-8?q?rename:=20=EC=84=9C=EB=B9=84=EC=8A=A4=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/study/api/StudentStudyHistoryController.java | 6 +++--- ...yHistoryService.java => StudentStudyHistoryService.java} | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/main/java/com/gdschongik/gdsc/domain/study/application/{StudyHistoryService.java => StudentStudyHistoryService.java} (98%) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java index d0bddc58f..6415a9f27 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java @@ -1,6 +1,6 @@ package com.gdschongik.gdsc.domain.study.api; -import com.gdschongik.gdsc.domain.study.application.StudyHistoryService; +import com.gdschongik.gdsc.domain.study.application.StudentStudyHistoryService; import com.gdschongik.gdsc.domain.study.dto.request.RepositoryUpdateRequest; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -19,13 +19,13 @@ @RequiredArgsConstructor public class StudentStudyHistoryController { - private final StudyHistoryService studyHistoryService; + private final StudentStudyHistoryService studentStudyHistoryService; @Operation(summary = "레포지토리 입력", description = "레포지토리를 입력합니다. 이미 제출한 과제가 있다면 수정할 수 없습니다.") @PutMapping("/{studyHistoryId}/repository") public ResponseEntity updateRepository( @PathVariable Long studyHistoryId, @Valid @RequestBody RepositoryUpdateRequest request) { - studyHistoryService.updateRepository(studyHistoryId, request); + studentStudyHistoryService.updateRepository(studyHistoryId, request); return ResponseEntity.ok().build(); } } diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyHistoryService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java similarity index 98% rename from src/main/java/com/gdschongik/gdsc/domain/study/application/StudyHistoryService.java rename to src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java index 027c62ab5..ce45cb5cf 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudyHistoryService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java @@ -21,7 +21,7 @@ @Slf4j @Service @RequiredArgsConstructor -public class StudyHistoryService { +public class StudentStudyHistoryService { private final MemberUtil memberUtil; private final GithubClient githubClient; From 87555c5a4a12d433995866c8ee352bbbe3ed55f3 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Sun, 11 Aug 2024 14:40:01 +0900 Subject: [PATCH 12/14] =?UTF-8?q?docs:=20=EB=A1=9C=EA=B7=B8=EC=97=90=20?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=EB=90=9C=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EB=A7=81=ED=81=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/study/application/StudentStudyHistoryService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java index ce45cb5cf..e74513ced 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java @@ -45,7 +45,10 @@ public void updateRepository(Long studyHistoryId, RepositoryUpdateRequest reques studyHistory.updateRepositoryLink(request.repositoryLink()); studyHistoryRepository.save(studyHistory); - log.info("[StudyHistoryService] 레포지토리 입력: studyHistoryId={}", studyHistory.getId()); + log.info( + "[StudyHistoryService] 레포지토리 입력: studyHistoryId={}, repositoryLink={}", + studyHistory.getId(), + request.repositoryLink()); } private void validateRepositoryLink(String repositoryLink) { From 81b3b5c5ddde7cf851904978aafb8651863e0108 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Tue, 13 Aug 2024 08:01:54 +0900 Subject: [PATCH 13/14] =?UTF-8?q?feat:=20todo=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gdsc/domain/study/domain/StudyHistoryValidator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java index e742d43e0..c7ce4b0f7 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java @@ -24,6 +24,7 @@ public void validateApplyStudy(Study study, List currentMemberStud } // 이미 듣고 있는 스터디가 있는 경우 + // todo: StudyHistory가 아닌 Study의 isOngoning 호출하도록 수정 boolean isInOngoingStudy = currentMemberStudyHistories.stream().anyMatch(StudyHistory::isStudyOngoing); if (isInOngoingStudy) { From 1eb8af5af284f7e3a52cedb589fb6ce11844ace6 Mon Sep 17 00:00:00 2001 From: "chosw1002@naver.com" Date: Tue, 13 Aug 2024 08:13:57 +0900 Subject: [PATCH 14/14] =?UTF-8?q?feat:=20=EB=A0=88=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=86=8C=EC=9C=A0=EC=9E=90=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/StudentStudyHistoryController.java | 3 ++- .../application/StudentStudyHistoryService.java | 15 +++++++-------- .../study/domain/StudyHistoryValidator.java | 10 ++++++++-- .../gdsc/global/exception/ErrorCode.java | 4 +++- .../study/domain/StudyHistoryValidatorTest.java | 17 +++++++++++++++-- 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java index 6415a9f27..4d6c556ff 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/api/StudentStudyHistoryController.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; +import java.io.IOException; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; @@ -24,7 +25,7 @@ public class StudentStudyHistoryController { @Operation(summary = "레포지토리 입력", description = "레포지토리를 입력합니다. 이미 제출한 과제가 있다면 수정할 수 없습니다.") @PutMapping("/{studyHistoryId}/repository") public ResponseEntity updateRepository( - @PathVariable Long studyHistoryId, @Valid @RequestBody RepositoryUpdateRequest request) { + @PathVariable Long studyHistoryId, @Valid @RequestBody RepositoryUpdateRequest request) throws IOException { studentStudyHistoryService.updateRepository(studyHistoryId, request); return ResponseEntity.ok().build(); } diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java index e74513ced..df253f536 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/application/StudentStudyHistoryService.java @@ -13,8 +13,10 @@ import com.gdschongik.gdsc.global.exception.CustomException; import com.gdschongik.gdsc.global.util.MemberUtil; import com.gdschongik.gdsc.infra.client.github.GithubClient; +import java.io.IOException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.kohsuke.github.GHRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -30,7 +32,7 @@ public class StudentStudyHistoryService { private final StudyHistoryValidator studyHistoryValidator; @Transactional - public void updateRepository(Long studyHistoryId, RepositoryUpdateRequest request) { + public void updateRepository(Long studyHistoryId, RepositoryUpdateRequest request) throws IOException { Member currentMember = memberUtil.getCurrentMember(); StudyHistory studyHistory = studyHistoryRepository .findById(studyHistoryId) @@ -39,8 +41,10 @@ public void updateRepository(Long studyHistoryId, RepositoryUpdateRequest reques boolean isAnyAssignmentSubmitted = assignmentHistoryRepository.existsSubmittedAssignmentByMemberAndStudy(currentMember, study); - studyHistoryValidator.validateUpdateRepository(isAnyAssignmentSubmitted); - validateRepositoryLink(request.repositoryLink()); + String ownerRepo = getOwnerRepo(request.repositoryLink()); + GHRepository repository = githubClient.getRepository(ownerRepo); + studyHistoryValidator.validateUpdateRepository( + isAnyAssignmentSubmitted, String.valueOf(repository.getOwner().getId()), currentMember.getOauthId()); studyHistory.updateRepositoryLink(request.repositoryLink()); studyHistoryRepository.save(studyHistory); @@ -51,11 +55,6 @@ public void updateRepository(Long studyHistoryId, RepositoryUpdateRequest reques request.repositoryLink()); } - private void validateRepositoryLink(String repositoryLink) { - String ownerRepo = getOwnerRepo(repositoryLink); - githubClient.getRepository(ownerRepo); - } - private String getOwnerRepo(String repositoryLink) { int startIndex = repositoryLink.indexOf(GITHUB_DOMAIN) + GITHUB_DOMAIN.length(); return repositoryLink.substring(startIndex); diff --git a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java index c7ce4b0f7..2e2d19d82 100644 --- a/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java +++ b/src/main/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidator.java @@ -39,10 +39,16 @@ public void validateCancelStudyApply(Study study) { } } - public void validateUpdateRepository(boolean isAnyAssignmentSubmitted) { + public void validateUpdateRepository( + boolean isAnyAssignmentSubmitted, String repositoryOwnerOauthId, String currentMemberOauthId) { // 이미 제출한 과제가 있는 경우 if (isAnyAssignmentSubmitted) { - throw new CustomException(STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE); + throw new CustomException(STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE_ASSIGNMENT_ALREADY_SUBMITTED); + } + + // 레포지토리 소유자가 현 멤버가 아닌 경우 + if (!repositoryOwnerOauthId.equals(currentMemberOauthId)) { + throw new CustomException(STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE_OWNER_MISMATCH); } } } diff --git a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java index cceed6623..b17d81072 100644 --- a/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java +++ b/src/main/java/com/gdschongik/gdsc/global/exception/ErrorCode.java @@ -117,7 +117,9 @@ public enum ErrorCode { STUDY_HISTORY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 수강 기록입니다."), STUDY_HISTORY_DUPLICATE(HttpStatus.CONFLICT, "이미 해당 스터디를 신청했습니다."), STUDY_HISTORY_ONGOING_ALREADY_EXISTS(HttpStatus.CONFLICT, "이미 진행중인 스터디가 있습니다."), - STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE(HttpStatus.CONFLICT, "이미 제출한 과제가 있으므로 레포지토리를 수정할 수 없습니다."), + STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE_ASSIGNMENT_ALREADY_SUBMITTED( + HttpStatus.CONFLICT, "이미 제출한 과제가 있으므로 레포지토리를 수정할 수 없습니다."), + STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE_OWNER_MISMATCH(HttpStatus.CONFLICT, "레포지토리 소유자가 현재 멤버와 다릅니다."), // Order ORDER_NOT_FOUND(HttpStatus.NOT_FOUND, "주문이 존재하지 않습니다."), diff --git a/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java index 447966d88..f72b97dba 100644 --- a/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java +++ b/src/test/java/com/gdschongik/gdsc/domain/study/domain/StudyHistoryValidatorTest.java @@ -1,5 +1,6 @@ package com.gdschongik.gdsc.domain.study.domain; +import static com.gdschongik.gdsc.global.common.constant.MemberConstant.*; import static com.gdschongik.gdsc.global.exception.ErrorCode.*; import static org.assertj.core.api.Assertions.*; @@ -106,9 +107,21 @@ class 레포지토리_입력시 { boolean isAnyAssignmentSubmitted = true; // when & then - assertThatThrownBy(() -> studyHistoryValidator.validateUpdateRepository(isAnyAssignmentSubmitted)) + assertThatThrownBy(() -> studyHistoryValidator.validateUpdateRepository( + isAnyAssignmentSubmitted, OAUTH_ID, OAUTH_ID)) .isInstanceOf(CustomException.class) - .hasMessage(STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE.getMessage()); + .hasMessage(STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE_ASSIGNMENT_ALREADY_SUBMITTED.getMessage()); + } + + @Test + void 레포지토리의_소유자와_현재_멤버가_일치하지_않는다면_실패한다() { + // given + String wrongOauthId = "1234567"; + + // when & then + assertThatThrownBy(() -> studyHistoryValidator.validateUpdateRepository(false, wrongOauthId, OAUTH_ID)) + .isInstanceOf(CustomException.class) + .hasMessage(STUDY_HISTORY_REPOSITORY_NOT_UPDATABLE_OWNER_MISMATCH.getMessage()); } } }