-
Notifications
You must be signed in to change notification settings - Fork 248
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
Step2 #353
Open
suzhanlee
wants to merge
24
commits into
next-step:suzhanlee
Choose a base branch
from
suzhanlee:step2
base: suzhanlee
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Step2 #353
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
588f420
feat : LMS step 2 전체적인 골격 생성
suzhanlee 007b730
refactor : DeleteHistory answer 정적 팩토리 메소드로 변수 줄이기
suzhanlee 427c601
refactor : DeleteHistory question 정적 팩토리 메소드로 변수 줄이기
suzhanlee 961a0e1
refactor : 사용하지 않는 getter, setter 제거
suzhanlee 2c93348
Docs : LMS step2 기능 목록 보완
suzhanlee 6f12941
feat : ImageSize 이미지의 width는 300픽셀 이상인지 검증하는 기능 추가
suzhanlee c0a7182
feat : ImageSize 이미지의 height는 200픽셀 이상인지 검증하는 기능 추가
suzhanlee 53c9333
feat : ImageSize width와 height의 비율은 3:2 인지 검증하는 기능 추가
suzhanlee cdad875
feat : ImageType 사용할 수 있는 이미지 타입인지 검증하는 기능 추가
suzhanlee d70eb14
feat : ImageCapacity 이미지 용량이 1MB 이하인지 검증하는 기능 추가
suzhanlee 9350996
feat : SessionStatus 강의를 수강할 수 있는지 알려주는 기능 추가
suzhanlee 4a989c7
feat : SessionParticipants 강의에 사람이 다 찼는지 확인하는 기능 추가
suzhanlee 6b93913
feat : Session 강의 타입에 따라 수강생을 등록하는 기능 추가
suzhanlee 680e35e
feat : SessionPeriod 강의가 시작했는지 확인하는 기능 추가
suzhanlee 6af0cd9
feat : CourseService 저장 및 조회 기능 추가
suzhanlee ee0b030
feat : ImageService 저장 및 조회 기능 추가
suzhanlee bb9310a
refactor : Enrollment 에게 Session의 강의 등록 책임 위임
suzhanlee 01c19ee
feat : SessionService 강의를 저장하고, 조회하는 기능 추가
suzhanlee 2ad8e47
feat : SessionService 수강 신청 기능 추가
suzhanlee 6df635f
test : SessionServiceTest 강의 수강 신청 테스트
suzhanlee 0998cc6
test : SessionServiceTest 강좌를 저장하는 기능 테스트
suzhanlee 9fda807
Style : 코드 서식 재정리 및 import 문 최적화
suzhanlee 707f33d
remove : 필요없는 클래스 삭제
suzhanlee 7ace3b4
fix : 테스트 오류나는 부분 코드 수정
suzhanlee File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,94 @@ | ||
# 학습 관리 시스템(Learning Management System) | ||
|
||
## 진행 방법 | ||
|
||
* 학습 관리 시스템의 수강신청 요구사항을 파악한다. | ||
* 요구사항에 대한 구현을 완료한 후 자신의 github 아이디에 해당하는 브랜치에 Pull Request(이하 PR)를 통해 코드 리뷰 요청을 한다. | ||
* 코드 리뷰 피드백에 대한 개선 작업을 하고 다시 PUSH한다. | ||
* 모든 피드백을 완료하면 다음 단계를 도전하고 앞의 과정을 반복한다. | ||
|
||
## 온라인 코드 리뷰 과정 | ||
|
||
* [텍스트와 이미지로 살펴보는 온라인 코드 리뷰 과정](https://github.com/next-step/nextstep-docs/tree/master/codereview) | ||
|
||
## LMS STEP 1 기능 목록 | ||
|
||
## LMS 기능 목록 | ||
* `Question` | ||
* [x] : 로그인 사용자, 질문자와 모든 답변자들이 같으면 답변을 삭제 상태로 바꿀 수 있다. | ||
* [x] : 질문이 삭제되면 삭제 히스토리에게 질문 삭제 요청을 보낸다. | ||
* [x] : 질문이 삭제되면 삭제 히스토리에게 질문에 대한 댓글들의 삭제 요청을 보낸다. | ||
* [x] : 질문이 삭제되면 삭제 히스토리에게 질문 삭제 요청을 보낸다. | ||
* [x] : 질문이 삭제되면 삭제 히스토리에게 질문에 대한 댓글들의 삭제 요청을 보낸다. | ||
* [x] : 삭제할 수 없다면 예외를 던진다. | ||
* [x] : 사용자와 질문자가 달라 삭제할 수 없다면 예외를 던진다. | ||
* [x] : 질문자와 답변자들이 달라 삭제할 수 없다면 예외를 던진다. | ||
* [x] : 사용자와 질문자가 달라 삭제할 수 없다면 예외를 던진다. | ||
* [x] : 질문자와 답변자들이 달라 삭제할 수 없다면 예외를 던진다. | ||
|
||
* `Answer` | ||
* [x] : 질문자와 답변자가 같은지 다른지 확인한다. | ||
* [x] : 질문이 삭제되면, 댓글도 삭제한다. | ||
|
||
## 수강 신청 기능 요구사항 | ||
|
||
* 과정(Course)은 기수 단위로 운영하며, 여러 개의 강의(Session)를 가질 수 있다. | ||
* 강의는 시작일과 종료일을 가진다. | ||
* 강의는 강의 커버 이미지 정보를 가진다. | ||
* 이미지 크기는 1MB 이하여야 한다. | ||
* 이미지 타입은 gif, jpg(jpeg 포함),, png, svg만 허용한다. | ||
* 이미지의 width는 300픽셀, height는 200픽셀 이상이어야 하며, width와 height의 비율은 3:2여야 한다. | ||
* 강의는 무료 강의와 유료 강의로 나뉜다. | ||
* 무료 강의는 최대 수강 인원 제한이 없다. | ||
* 유료 강의는 강의 최대 수강 인원을 초과할 수 없다. | ||
* 유료 강의는 수강생이 결제한 금액과 수강료가 일치할 때 수강 신청이 가능하다. | ||
* 강의 상태는 준비중, 모집중, 종료 3가지 상태를 가진다. | ||
* 강의 수강신청은 강의 상태가 모집중일 때만 가능하다. | ||
* 유료 강의의 경우 결제는 이미 완료한 것으로 가정하고 이후 과정을 구현한다. | ||
* 결제를 완료한 결제 정보는 payments 모듈을 통해 관리되며, 결제 정보는 Payment 객체에 담겨 반한된다. | ||
|
||
## LMS STEP 2 기능 목록 | ||
|
||
* `Course` : 과정 | ||
* [] : | ||
|
||
* `Session` : 강의 | ||
* [x] : 강의 타입에 따라 수강생을 등록한다. | ||
|
||
* `SessionParticipants` : 강의 수강 인원 정보 | ||
* [x] : 강의에 사람이 다 찼는지 확인한다. | ||
|
||
* `SessionStatus` : 강의 상태 | ||
* [x] : 강의를 수강할 수 있는지 알려준다. | ||
|
||
* `SessionType` : 강의 타입 | ||
* [x] : 강의 타입이 유료인지 무료인지 확인한다. | ||
|
||
* `SessionPeriod` : 강의 기간 | ||
* [x] : 강의가 시작했는지 확인한다. | ||
|
||
* `Image` : 이미지 | ||
* [] : | ||
|
||
* `ImageSize` : 이미지 사이즈 | ||
* [x] : 이미지의 width는 300픽셀 이상인지 검증한다. | ||
* [x] : 이미지의 height는 200픽셀 이상인지 검증한다. | ||
* [x] : width와 height의 비율은 3:2 인지 검증한다. | ||
|
||
* `ImageType` : 이미지 타입 | ||
* [x] : 사용할 수 있는 이미지 타입인지 검증한다. | ||
|
||
* `ImageCapacityType` : 이미지 용량 타입 | ||
* [x] : 이미지 용량 이름으로 이미지 용량 타입을 찾는다. | ||
|
||
* `ImageCapacity` : 이미지 용량 | ||
* [x] : 이미지 용량이 1MB 이하인지 검증한다. | ||
|
||
* `Enrollment` : 등록 | ||
* [x] : 유료 강의 수강 신청을 한다. | ||
* [x] : 무료 강의 수강 신청을 한다. | ||
* [x] : 유료 강의의 경우, 수강 인원이 모두 채워지면 예외를 던진다. | ||
|
||
* `Payments` : 결제 정보들 | ||
* [] : | ||
|
||
* `SessionPayment` : 결제 정보 | ||
* [] : | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,10 @@ | ||
package nextstep.courses.domain; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import nextstep.session.domain.Session; | ||
|
||
public class Course { | ||
private Long id; | ||
|
@@ -13,13 +17,19 @@ public class Course { | |
|
||
private LocalDateTime updatedAt; | ||
|
||
private List<Session> sessions = new ArrayList<>(); | ||
|
||
public Course() { | ||
} | ||
|
||
public Course(String title, Long creatorId) { | ||
this(0L, title, creatorId, LocalDateTime.now(), null); | ||
} | ||
|
||
public Course(Long id, String title, Long creatorId) { | ||
this(id, title, creatorId, LocalDateTime.now(), null); | ||
} | ||
|
||
public Course(Long id, String title, Long creatorId, LocalDateTime createdAt, LocalDateTime updatedAt) { | ||
this.id = id; | ||
this.title = title; | ||
|
@@ -28,6 +38,14 @@ public Course(Long id, String title, Long creatorId, LocalDateTime createdAt, Lo | |
this.updatedAt = updatedAt; | ||
} | ||
|
||
public void addSession(Session session) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
sessions.add(session); | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public String getTitle() { | ||
return title; | ||
} | ||
|
@@ -40,6 +58,28 @@ public LocalDateTime getCreatedAt() { | |
return createdAt; | ||
} | ||
|
||
public List<Session> getSessions() { | ||
return sessions; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
Course course = (Course) o; | ||
return Objects.equals(title, course.title) && Objects.equals(creatorId, course.creatorId) | ||
&& Objects.equals(sessions, course.sessions); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(title, creatorId, sessions); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "Course{" + | ||
|
13 changes: 13 additions & 0 deletions
13
src/main/java/nextstep/courses/dto/CreateCourseRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package nextstep.courses.dto; | ||
|
||
import nextstep.courses.domain.Course; | ||
|
||
public class CreateCourseRequest { | ||
|
||
private String title; | ||
private Long creatorId; | ||
|
||
public Course toEntity() { | ||
return new Course(title, creatorId); | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
src/main/java/nextstep/courses/infrastructure/MockCourseRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package nextstep.courses.infrastructure; | ||
|
||
import java.util.LinkedHashMap; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import nextstep.courses.domain.Course; | ||
import nextstep.courses.domain.CourseRepository; | ||
|
||
public class MockCourseRepository implements CourseRepository { | ||
|
||
private Map<Integer, Course> courseStorage = new LinkedHashMap<>(); | ||
|
||
public MockCourseRepository() { | ||
this.courseStorage.put(1, new Course(1L, "코스", 1L)); | ||
} | ||
|
||
@Override | ||
public int save(Course course) { | ||
long courseId = Optional.ofNullable(course.getId()) | ||
.orElseGet(() -> (long) (courseStorage.size() + 1)); | ||
int intCourseId = Math.toIntExact(courseId); | ||
courseStorage.put(intCourseId, course); | ||
return intCourseId; | ||
} | ||
|
||
@Override | ||
public Course findById(Long id) { | ||
return Optional.ofNullable(courseStorage.get(Integer.parseInt(String.valueOf(id)))) | ||
.orElseThrow(() -> new IllegalStateException("과정을 찾을 수 없습니다.")); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package nextstep.courses.sevice; | ||
|
||
import nextstep.courses.domain.Course; | ||
import nextstep.courses.domain.CourseRepository; | ||
import nextstep.courses.dto.CreateCourseRequest; | ||
|
||
public class CourseService { | ||
|
||
private final CourseRepository courseRepository; | ||
|
||
public CourseService(CourseRepository courseRepository) { | ||
this.courseRepository = courseRepository; | ||
} | ||
|
||
public int saveCourse(CreateCourseRequest request) { | ||
return courseRepository.save(request.toEntity()); | ||
} | ||
|
||
public void saveCourse(Course course) { | ||
courseRepository.save(course); | ||
} | ||
|
||
public Course findCourse(Long courseId) { | ||
return courseRepository.findById(courseId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package nextstep.image.domain; | ||
|
||
import java.util.Objects; | ||
|
||
public class Image { | ||
|
||
private ImageCapacity imageCapacity; | ||
|
||
private ImageType imageType; | ||
|
||
private ImageSize imageSize; | ||
|
||
public Image(ImageCapacity imageCapacity, ImageType imageType, ImageSize imageSize) { | ||
this.imageCapacity = imageCapacity; | ||
this.imageType = imageType; | ||
this.imageSize = imageSize; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
Image image = (Image) o; | ||
return Objects.equals(imageCapacity, image.imageCapacity) && imageType == image.imageType | ||
&& Objects.equals(imageSize, image.imageSize); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(imageCapacity, imageType, imageSize); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package nextstep.image.domain; | ||
|
||
import java.util.Objects; | ||
import nextstep.image.exception.OutOfRangeCapacityException; | ||
import nextstep.image.exception.OutOfRangeCapacityTypeException; | ||
|
||
public class ImageCapacity { | ||
|
||
public static final String OUT_OF_RANGE_CAPACITY_EXCEPTION = "이미지 용량이 1MB를 넘습니다."; | ||
public static final String OUT_OF_RANGE_CAPACITY_TYPE_EXCEPTION = "이미지 용량 타입이 MB를 넘습니다."; | ||
|
||
private long value; | ||
private ImageCapacityType imageCapacityType; | ||
|
||
public ImageCapacity(long value, ImageCapacityType imageCapacityType) { | ||
validateImageCapacity(value, imageCapacityType); | ||
this.value = value; | ||
this.imageCapacityType = imageCapacityType; | ||
} | ||
|
||
public ImageCapacity(long value, String capacityTypeName) { | ||
this(value, ImageCapacityType.findByName(capacityTypeName)); | ||
} | ||
|
||
private static void validateImageCapacity(long value, ImageCapacityType imageCapacityType) { | ||
validateCapacityTypeRange(imageCapacityType); | ||
validateCapacityRange(value, imageCapacityType); | ||
} | ||
|
||
private static void validateCapacityTypeRange(ImageCapacityType imageCapacityType) { | ||
if (imageCapacityType.isGreaterThanMB()) { | ||
throw new OutOfRangeCapacityTypeException(OUT_OF_RANGE_CAPACITY_TYPE_EXCEPTION); | ||
} | ||
} | ||
|
||
private static void validateCapacityRange(long value, ImageCapacityType imageCapacityType) { | ||
if (outOfRange(value, imageCapacityType)) { | ||
throw new OutOfRangeCapacityException(OUT_OF_RANGE_CAPACITY_EXCEPTION); | ||
} | ||
} | ||
|
||
private static boolean outOfRange(long value, ImageCapacityType imageCapacityType) { | ||
return imageCapacityType.isLessThanMB() && value > 1; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
ImageCapacity that = (ImageCapacity) o; | ||
return value == that.value && imageCapacityType == that.imageCapacityType; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(value, imageCapacityType); | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
src/main/java/nextstep/image/domain/ImageCapacityType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package nextstep.image.domain; | ||
|
||
import java.util.Arrays; | ||
import nextstep.image.exception.CannotFindImageCapacityTypeException; | ||
|
||
public enum ImageCapacityType { | ||
|
||
KB("kb"), | ||
MB("mb"), | ||
GB("gb"); | ||
|
||
public static final String CANNOT_FIND_IMAGE_CAPACITY_TYPE_EXCEPTION = "이미지 용량 타입을 찾을 수 없습니다."; | ||
|
||
private final String name; | ||
|
||
ImageCapacityType(String name) { | ||
this.name = name; | ||
} | ||
|
||
public static ImageCapacityType findByName(String name) { | ||
return Arrays.stream(values()) | ||
.filter(imageCapacityType -> imageCapacityType.name.equals(name)) | ||
.findFirst() | ||
.orElseThrow(() -> new CannotFindImageCapacityTypeException(CANNOT_FIND_IMAGE_CAPACITY_TYPE_EXCEPTION)); | ||
} | ||
|
||
public boolean isLessThanMB() { | ||
return !this.equals(KB); | ||
} | ||
|
||
public boolean isGreaterThanMB() { | ||
return this.equals(GB); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저는 생성자를 다양하게 사용하기 위해
초기화는 생성자에서 해줄것 같아요.
생성자가 다양하면, 테스트 할때
assSession
같은 메소드를 사용하지 않고도바로
Course
를 생성할 수 있는게 장점인것 같아요.