Skip to content

Commit

Permalink
feat: 과제 스터디 생성 로직 구현 (#869)
Browse files Browse the repository at this point in the history
* feat: 스터디 정적 팩토리 메서드를 라이브 및 과제 전용으로 분리

* feat: 라이브 세션 관련 필드에 nullable 추가

* docs: 투두 추가

* docs: API 설명 보완

* feat: StudyType에서 라이브 타입 여부 판정하는 메서드 추가

* feat: 스터디 팩토리에 라이브 및 과제 타입에 따른 분기 추가

* feat: 라이브 및 과제 구분 스터디세션 엔티티에도 적용

* test: 스터디 팩토리 관련 테스트 변경 및 추가

* feat: 접근제어자 변경
  • Loading branch information
uwoobeat authored Feb 8, 2025
1 parent 258fa76 commit 613ba13
Show file tree
Hide file tree
Showing 8 changed files with 189 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ public enum StudyType {
OFFLINE("오프라인 스터디");

private final String value;

public boolean isLive() {
return this == ONLINE || this == OFFLINE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class AdminStudyControllerV2 {

private final AdminStudyServiceV2 adminStudyServiceV2;

@Operation(summary = "스터디 개설", description = "스터디를 개설합니다. 빈 스터디회차를 함께 생성합니다.")
@Operation(summary = "스터디 개설", description = "스터디를 개설합니다. 빈 스터디회차를 함께 생성합니다. 과제 스터디의 경우 라이브 세션 관련 필드는 null이어야 합니다.")
@PostMapping
public ResponseEntity<Void> createStudy(@Valid @RequestBody StudyCreateRequest request) {
adminStudyServiceV2.createStudy(request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,52 @@ public StudyV2 create(
String discordRoleId,
Member mentor,
AttendanceNumberGenerator attendanceNumberGenerator) {
StudyV2 study = StudyV2.create(
if (type.isLive()) {
return createLive(
type,
title,
description,
descriptionNotionLink,
semester,
totalRound,
dayOfWeek,
startTime,
endTime,
applicationPeriod,
discordChannelId,
discordRoleId,
mentor,
attendanceNumberGenerator);
} else {
return createAssignment(
title,
description,
descriptionNotionLink,
semester,
totalRound,
applicationPeriod,
discordChannelId,
discordRoleId,
mentor);
}
}

private StudyV2 createLive(
StudyType type,
String title,
String description,
String descriptionNotionLink,
Semester semester,
Integer totalRound,
DayOfWeek dayOfWeek,
LocalTime startTime,
LocalTime endTime,
Period applicationPeriod,
String discordChannelId,
String discordRoleId,
Member mentor,
AttendanceNumberGenerator attendanceNumberGenerator) {
StudyV2 study = StudyV2.createLive(
type,
title,
description,
Expand All @@ -47,7 +92,34 @@ public StudyV2 create(
mentor);

IntStream.rangeClosed(1, totalRound)
.forEach(round -> StudySessionV2.createEmpty(round, attendanceNumberGenerator.generate(), study));
.forEach(
round -> StudySessionV2.createEmptyForLive(round, attendanceNumberGenerator.generate(), study));

return study;
}

private StudyV2 createAssignment(
String title,
String description,
String descriptionNotionLink,
Semester semester,
Integer totalRound,
Period applicationPeriod,
String discordChannelId,
String discordRoleId,
Member mentor) {
StudyV2 study = StudyV2.createAssignment(
title,
description,
descriptionNotionLink,
semester,
totalRound,
applicationPeriod,
discordChannelId,
discordRoleId,
mentor);

IntStream.rangeClosed(1, totalRound).forEach(round -> StudySessionV2.createEmptyForAssignment(round, study));

return study;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,15 @@ private StudySessionV2(
studyV2.getStudySessions().add(this);
}

public static void createEmpty(Integer position, String lessonAttendanceNumber, StudyV2 studyV2) {
public static void createEmptyForLive(Integer position, String lessonAttendanceNumber, StudyV2 studyV2) {
StudySessionV2.builder()
.position(position)
.lessonAttendanceNumber(lessonAttendanceNumber)
.studyV2(studyV2)
.build();
}

public static void createEmptyForAssignment(Integer position, StudyV2 studyV2) {
StudySessionV2.builder().position(position).studyV2(studyV2).build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
import com.gdschongik.gdsc.domain.common.vo.Semester;
import com.gdschongik.gdsc.domain.member.domain.Member;
import com.gdschongik.gdsc.domain.study.domain.StudyType;
import com.gdschongik.gdsc.global.exception.CustomException;
import com.gdschongik.gdsc.global.exception.ErrorCode;
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
Expand Down Expand Up @@ -123,7 +125,10 @@ private StudyV2(
this.mentor = mentor;
}

public static StudyV2 create(
/**
* 라이브 스터디를 생성합니다.
*/
public static StudyV2 createLive(
StudyType type,
String title,
String description,
Expand All @@ -137,6 +142,7 @@ public static StudyV2 create(
String discordChannelId,
String discordRoleId,
Member mentor) {
validateLiveStudy(type);
return StudyV2.builder()
.type(type)
.title(title)
Expand All @@ -153,4 +159,37 @@ public static StudyV2 create(
.mentor(mentor)
.build();
}

private static void validateLiveStudy(StudyType type) {
if (!type.isLive()) {
throw new CustomException(ErrorCode.STUDY_NOT_CREATABLE_NOT_LIVE);
}
}

/**
* 과제 스터디를 생성합니다.
*/
public static StudyV2 createAssignment(
String title,
String description,
String descriptionNotionLink,
Semester semester,
Integer totalRound,
Period applicationPeriod,
String discordChannelId,
String discordRoleId,
Member mentor) {
return StudyV2.builder()
.type(StudyType.ASSIGNMENT)
.title(title)
.description(description)
.descriptionNotionLink(descriptionNotionLink)
.semester(semester)
.totalRound(totalRound)
.applicationPeriod(applicationPeriod)
.discordChannelId(discordChannelId)
.discordRoleId(discordRoleId)
.mentor(mentor)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.gdschongik.gdsc.domain.common.vo.Period;
import com.gdschongik.gdsc.domain.common.vo.Semester;
import com.gdschongik.gdsc.domain.study.domain.StudyType;
import jakarta.annotation.Nullable;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;
import java.time.DayOfWeek;
Expand All @@ -16,9 +17,11 @@ public record StudyCreateRequest(
String descriptionNotionLink,
@NotNull Semester semester,
@NotNull @Positive Integer totalRound,
DayOfWeek dayOfWeek,
LocalTime startTime,
LocalTime endTime,
@Nullable DayOfWeek dayOfWeek,
@Nullable LocalTime startTime,
@Nullable LocalTime endTime,
@NotNull Period applicationPeriod,
String discordChannelId,
String discordRoleId) {}
String discordRoleId) {
// TODO: 라이브 세션 관련 필드의 경우 VO로 묶기
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ public enum ErrorCode {
STUDY_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디입니다."),
STUDY_NOT_APPLICABLE(HttpStatus.CONFLICT, "스터디 신청기간이 아닙니다."),
STUDY_NOT_CANCELABLE_APPLICATION_PERIOD(HttpStatus.CONFLICT, "스터디 신청기간이 아니라면 취소할 수 없습니다."),
STUDY_NOT_CREATABLE_NOT_LIVE(HttpStatus.INTERNAL_SERVER_ERROR, "온라인 및 오프라인 타입만 라이브 스터디로 생성할 수 있습니다."),

// StudyDetail
STUDY_DETAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 스터디 상세 정보입니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,34 @@ public String generate() {
assertThat(study.getStudySessions()).hasSize(8);
}

@Test
void 과제_스터디_생성시_라이브_세션_관련_필드가_제외된다() {
// given
Member mentor = fixtureHelper.createMentor(1L);

// when
StudyV2 study = studyFactory.create(
StudyType.ASSIGNMENT,
STUDY_TITLE,
STUDY_DESCRIPTION,
STUDY_DESCRIPTION_NOTION_LINK,
STUDY_SEMESTER,
TOTAL_ROUND,
DAY_OF_WEEK,
STUDY_START_TIME,
STUDY_END_TIME,
STUDY_APPLICATION_PERIOD,
STUDY_DISCORD_CHANNEL_ID,
STUDY_DISCORD_ROLE_ID,
mentor,
null);

// then
assertThat(study.getDayOfWeek()).isNull();
assertThat(study.getStartTime()).isNull();
assertThat(study.getEndTime()).isNull();
}

@Test
void 스터디_생성시_스터디회차는_순서대로_position이_지정되어_생성된다() {
// given
Expand Down Expand Up @@ -79,7 +107,7 @@ public String generate() {
}

@Test
void 스터디_생성시_각_스터디회차에_출석번호가_생성된다() {
void 라이브_스터디_생성시_각_스터디회차에_출석번호가_생성된다() {
// given
Member mentor = fixtureHelper.createMentor(1L);
AttendanceNumberGenerator generator = new FixedAttendanceNumberGenerator();
Expand All @@ -106,4 +134,32 @@ public String generate() {
.extracting(StudySessionV2::getLessonAttendanceNumber)
.containsOnly("0000");
}

@Test
void 과제_스터디_생성시_스터디회차에_출석번호가_생성되지_않는다() {
// given
Member mentor = fixtureHelper.createMentor(1L);

// when
StudyV2 study = studyFactory.create(
StudyType.ASSIGNMENT,
STUDY_TITLE,
STUDY_DESCRIPTION,
STUDY_DESCRIPTION_NOTION_LINK,
STUDY_SEMESTER,
TOTAL_ROUND,
DAY_OF_WEEK,
STUDY_START_TIME,
STUDY_END_TIME,
STUDY_APPLICATION_PERIOD,
STUDY_DISCORD_CHANNEL_ID,
STUDY_DISCORD_ROLE_ID,
mentor,
null);

// then
assertThat(study.getStudySessions())
.extracting(StudySessionV2::getLessonAttendanceNumber)
.containsOnly((String) null);
}
}

0 comments on commit 613ba13

Please sign in to comment.