Skip to content

Commit

Permalink
fix: merge conflict 해결하기
Browse files Browse the repository at this point in the history
  • Loading branch information
AlmondBreez3 committed Aug 18, 2024
2 parents 22d0afc + e48c72d commit 846ffa5
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.gdschongik.gdsc.domain.study.domain;

import static com.gdschongik.gdsc.domain.study.domain.AssignmentSubmissionStatus.*;
import static com.gdschongik.gdsc.domain.study.domain.SubmissionFailureType.*;
import static com.gdschongik.gdsc.global.exception.ErrorCode.*;

import com.gdschongik.gdsc.domain.common.model.BaseEntity;
import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.global.exception.CustomException;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
Expand All @@ -14,6 +17,7 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
Expand Down Expand Up @@ -44,6 +48,8 @@ public class AssignmentHistory extends BaseEntity {

private Long contentLength;

private LocalDateTime committedAt;

@Enumerated(EnumType.STRING)
private AssignmentSubmissionStatus submissionStatus;

Expand All @@ -54,27 +60,50 @@ public class AssignmentHistory extends BaseEntity {
private AssignmentHistory(
StudyDetail studyDetail,
Member member,
String submissionLink,
String commitHash,
Long contentLength,
AssignmentSubmissionStatus submissionStatus) {
AssignmentSubmissionStatus submissionStatus,
SubmissionFailureType submissionFailureType) {
this.studyDetail = studyDetail;
this.member = member;
this.submissionLink = submissionLink;
this.commitHash = commitHash;
this.contentLength = contentLength;
this.submissionStatus = submissionStatus;
this.submissionFailureType = submissionFailureType;
}

public static AssignmentHistory create(StudyDetail studyDetail, Member member) {
return AssignmentHistory.builder()
.studyDetail(studyDetail)
.member(member)
.submissionStatus(AssignmentSubmissionStatus.PENDING)
.submissionStatus(FAILURE)
.submissionFailureType(NOT_SUBMITTED)
.build();
}

// 데이터 조회 로직

public boolean isSubmitted() {
return submissionStatus == SUCCESS || submissionStatus == FAILURE;
return submissionFailureType != NOT_SUBMITTED;
}

// 데이터 변경 로직

public void success(String submissionLink, String commitHash, Long contentLength, LocalDateTime committedAt) {
this.submissionLink = submissionLink;
this.commitHash = commitHash;
this.contentLength = contentLength;
this.committedAt = committedAt;
this.submissionStatus = SUCCESS;
this.submissionFailureType = NONE;
}

public void fail(SubmissionFailureType submissionFailureType) {
if (submissionFailureType == NOT_SUBMITTED || submissionFailureType == NONE) {
throw new CustomException(ASSIGNMENT_INVALID_FAILURE_TYPE);
}

this.submissionLink = null;
this.commitHash = null;
this.contentLength = null;
this.committedAt = null;
this.submissionStatus = FAILURE;
this.submissionFailureType = submissionFailureType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
@Getter
@RequiredArgsConstructor
public enum AssignmentSubmissionStatus {
PENDING("제출 전"),
// TODO: 클라이언트 응답에는 PENDING 상태 필요하므로, 추후 응답용 enum 클래스 생성 구현
FAILURE("제출 실패"),
SUCCESS("제출 성공"),
CANCELLED("과제 휴강"); // TODO: 제거 및 DB에서 삭제
SUCCESS("제출 성공");

private final String value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
@Getter
@RequiredArgsConstructor
public enum SubmissionFailureType {
NOT_SUBMITTED("미제출"),
NONE("실패 없음"), // 제출상태 성공 시 사용
NOT_SUBMITTED("미제출"), // 기본값
WORD_COUNT_INSUFFICIENT("글자수 부족"),
LOCATION_UNIDENTIFIABLE("위치 확인불가");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public enum ErrorCode {
ORDER_FINAL_PAYMENT_AMOUNT_MISMATCH(HttpStatus.CONFLICT, "주문 최종결제금액은 주문총액에서 할인금액을 뺀 값이어야 합니다."),

// Assignment
ASSIGNMENT_CAN_NOT_BE_UPDATED(HttpStatus.CONFLICT, "휴강인 과제는 수정할 수 없습니다."),
ASSIGNMENT_INVALID_FAILURE_TYPE(HttpStatus.CONFLICT, "유효하지 않은 제출 실패사유입니다."),
ASSIGNMENT_DEADLINE_INVALID(HttpStatus.CONFLICT, "과제 마감 기한이 현재보다 빠릅니다."),
ASSIGNMENT_STUDY_NOT_APPLIED(HttpStatus.CONFLICT, "해당 스터디에 대한 수강신청 기록이 존재하지 않습니다."),
ASSIGNMENT_SUBMIT_NOT_STARTED(HttpStatus.CONFLICT, "아직 과제가 시작되지 않았습니다."),
Expand All @@ -161,8 +161,11 @@ public enum ErrorCode {

// Github
GITHUB_REPOSITORY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 레포지토리입니다."),
GITHUB_ASSIGNMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 과제 파일입니다.");

GITHUB_CONTENT_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 파일입니다."),
GITHUB_FILE_READ_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "깃허브 파일 읽기에 실패했습니다."),
GITHUB_COMMIT_DATE_FETCH_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "깃허브 커밋 날짜 조회에 실패했습니다."),
GITHUB_ASSIGNMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 과제 파일입니다."),
;
private final HttpStatus status;
private final String message;
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.gdschongik.gdsc.infra.github.client;

import static com.gdschongik.gdsc.global.common.constant.GithubConstant.*;
import static com.gdschongik.gdsc.global.exception.ErrorCode.*;

import com.gdschongik.gdsc.global.exception.CustomException;
import com.gdschongik.gdsc.global.exception.ErrorCode;
import com.gdschongik.gdsc.infra.github.dto.response.GithubAssignmentSubmissionResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import lombok.RequiredArgsConstructor;
import org.kohsuke.github.GHCommit;
import org.kohsuke.github.GHContent;
Expand All @@ -25,35 +27,55 @@ public GHRepository getRepository(String ownerRepo) {
try {
return github.getRepository(ownerRepo);
} catch (IOException e) {
throw new CustomException(ErrorCode.GITHUB_REPOSITORY_NOT_FOUND);
throw new CustomException(GITHUB_REPOSITORY_NOT_FOUND);
}
}

public GithubAssignmentSubmissionResponse getLatestAssignmentSubmission(String repo, int week) {
GHRepository ghRepository = getRepository(repo);
String assignmentPath = GITHUB_ASSIGNMENT_PATH.formatted(week);

// GHContent#getSize() 의 경우 한글 문자열을 byte 단위로 계산하기 때문에, 직접 content를 읽어서 길이를 계산
GHContent ghContent = getFileContent(ghRepository, assignmentPath);
String content = readFileContent(ghContent);

GHCommit ghLatestCommit = ghRepository
.queryCommits()
.path(assignmentPath)
.list()
.withPageSize(1)
.iterator()
.next();

LocalDateTime committedAt = getCommitDate(ghLatestCommit)
.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();

return new GithubAssignmentSubmissionResponse(ghLatestCommit.getSHA1(), content.length(), committedAt);
}

private GHContent getFileContent(GHRepository ghRepository, String filePath) {
try {
return ghRepository.getFileContent(filePath);
} catch (IOException e) {
throw new CustomException(GITHUB_CONTENT_NOT_FOUND);
}
}

private String readFileContent(GHContent ghContent) {
try (InputStream inputStream = ghContent.read()) {
return new String(inputStream.readAllBytes());
} catch (IOException e) {
throw new CustomException(GITHUB_FILE_READ_FAILED);
}
}

private Date getCommitDate(GHCommit ghLatestCommit) {
try {
GHRepository ghRepository = getRepository(repo);
String assignmentPath = GITHUB_ASSIGNMENT_PATH.formatted(week);

// GHContent#getSize() 의 경우 한글 문자열을 byte 단위로 계산하기 때문에, 직접 content를 읽어서 길이를 계산
GHContent ghContent = ghRepository.getFileContent(assignmentPath);
String content = new String(ghContent.read().readAllBytes());

GHCommit ghLatestCommit = ghRepository
.queryCommits()
.path(assignmentPath)
.list()
.toList()
.get(0);

LocalDateTime committedAt = ghLatestCommit
.getCommitDate()
.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();

return new GithubAssignmentSubmissionResponse(ghLatestCommit.getSHA1(), content.length(), committedAt);
return ghLatestCommit.getCommitDate();
} catch (IOException e) {
throw new CustomException(ErrorCode.GITHUB_ASSIGNMENT_NOT_FOUND);
throw new CustomException(GITHUB_COMMIT_DATE_FETCH_FAILED);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package com.gdschongik.gdsc.domain.study.domain;

import static com.gdschongik.gdsc.global.common.constant.StudyConstant.*;
import static com.gdschongik.gdsc.global.exception.ErrorCode.*;
import static org.assertj.core.api.Assertions.*;

import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.recruitment.domain.vo.Period;
import com.gdschongik.gdsc.global.exception.CustomException;
import com.gdschongik.gdsc.helper.FixtureHelper;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

class AssignmentHistoryTest {

FixtureHelper fixtureHelper = new FixtureHelper();

private Member createMember(Long id) {
return fixtureHelper.createAssociateMember(id);
}

private Study createStudyWithMentor(Long mentorId) {
Period period = Period.createPeriod(STUDY_START_DATETIME, STUDY_END_DATETIME);
Period applicationPeriod =
Period.createPeriod(STUDY_START_DATETIME.minusDays(7), STUDY_START_DATETIME.minusDays(1));
return fixtureHelper.createStudyWithMentor(mentorId, period, applicationPeriod);
}

private StudyDetail createStudyDetailWithAssignment(Study study) {
return fixtureHelper.createStudyDetailWithAssignment(
study, STUDY_DETAIL_START_DATETIME, STUDY_DETAIL_END_DATETIME, STUDY_ASSIGNMENT_DEADLINE_DATETIME);
}

@Nested
class_과제이력_생성할때 {

@Test
void 제출상태는_FAILURE이다() {
// given
Member member = createMember(1L);
Study study = createStudyWithMentor(1L);
StudyDetail studyDetail = createStudyDetailWithAssignment(study);

// when
AssignmentHistory assignmentHistory = AssignmentHistory.create(studyDetail, member);

// then
assertThat(assignmentHistory.getSubmissionStatus()).isEqualTo(AssignmentSubmissionStatus.FAILURE);
}

@Test
void 실패사유는_NOT_SUBMITTED이다() {
// given
Member member = createMember(1L);
Study study = createStudyWithMentor(1L);
StudyDetail studyDetail = createStudyDetailWithAssignment(study);

// when
AssignmentHistory assignmentHistory = AssignmentHistory.create(studyDetail, member);

// then
assertThat(assignmentHistory.getSubmissionFailureType()).isEqualTo(SubmissionFailureType.NOT_SUBMITTED);
}
}

@Nested
class 과제이력_제출_성공할때 {

@Test
void 제출상태는_SUCCESS이다() {
// given
Member member = createMember(1L);
Study study = createStudyWithMentor(1L);
StudyDetail studyDetail = createStudyDetailWithAssignment(study);
AssignmentHistory assignmentHistory = AssignmentHistory.create(studyDetail, member);

// when
assignmentHistory.success(SUBMISSION_LINK, COMMIT_HASH, CONTENT_LENGTH, COMMITTED_AT);
}

@Test
void 실패사유는_NONE이다() {
// given
Member member = createMember(1L);
Study study = createStudyWithMentor(1L);
StudyDetail studyDetail = createStudyDetailWithAssignment(study);
AssignmentHistory assignmentHistory = AssignmentHistory.create(studyDetail, member);

// when
assignmentHistory.success(SUBMISSION_LINK, COMMIT_HASH, CONTENT_LENGTH, COMMITTED_AT);

// then
assertThat(assignmentHistory.getSubmissionFailureType()).isEqualTo(SubmissionFailureType.NONE);
}
}

@Nested
class 과제이력_제출_실패할때 {

@Test
void 제출상태는_FAILURE이다() {
// given
Member member = createMember(1L);
Study study = createStudyWithMentor(1L);
StudyDetail studyDetail = createStudyDetailWithAssignment(study);
AssignmentHistory assignmentHistory = AssignmentHistory.create(studyDetail, member);
assignmentHistory.success(SUBMISSION_LINK, COMMIT_HASH, CONTENT_LENGTH, COMMITTED_AT);

// when
assignmentHistory.fail(SubmissionFailureType.WORD_COUNT_INSUFFICIENT);

// then
assertThat(assignmentHistory.getSubmissionStatus()).isEqualTo(AssignmentSubmissionStatus.FAILURE);
}

@Test
void 실패사유는_NOT_SUBMITTED가_될수없다() {
// given
Member member = createMember(1L);
Study study = createStudyWithMentor(1L);
StudyDetail studyDetail = createStudyDetailWithAssignment(study);
AssignmentHistory assignmentHistory = AssignmentHistory.create(studyDetail, member);
assignmentHistory.success(SUBMISSION_LINK, COMMIT_HASH, CONTENT_LENGTH, COMMITTED_AT);

// when, then
assertThatThrownBy(() -> assignmentHistory.fail(SubmissionFailureType.NOT_SUBMITTED))
.isInstanceOf(CustomException.class)
.hasMessageContaining(ASSIGNMENT_INVALID_FAILURE_TYPE.getMessage());
}

@Test
void 실패사유는_NONE_될수없다() {
// given
Member member = createMember(1L);
Study study = createStudyWithMentor(1L);
StudyDetail studyDetail = createStudyDetailWithAssignment(study);
AssignmentHistory assignmentHistory = AssignmentHistory.create(studyDetail, member);
assignmentHistory.success(SUBMISSION_LINK, COMMIT_HASH, CONTENT_LENGTH, COMMITTED_AT);

// when, then
assertThatThrownBy(() -> assignmentHistory.fail(SubmissionFailureType.NONE))
.isInstanceOf(CustomException.class)
.hasMessageContaining(ASSIGNMENT_INVALID_FAILURE_TYPE.getMessage());
}

@Test
void 기존_제출정보는_삭제된다() {
// given
Member member = createMember(1L);
Study study = createStudyWithMentor(1L);
StudyDetail studyDetail = createStudyDetailWithAssignment(study);
AssignmentHistory assignmentHistory = AssignmentHistory.create(studyDetail, member);
assignmentHistory.success(SUBMISSION_LINK, COMMIT_HASH, CONTENT_LENGTH, COMMITTED_AT);

// when
assignmentHistory.fail(SubmissionFailureType.WORD_COUNT_INSUFFICIENT);

// then
assertThat(assignmentHistory.getSubmissionLink()).isNull();
assertThat(assignmentHistory.getCommitHash()).isNull();
assertThat(assignmentHistory.getContentLength()).isNull();
assertThat(assignmentHistory.getCommittedAt()).isNull();
}
}
}
Loading

0 comments on commit 846ffa5

Please sign in to comment.