-
Notifications
You must be signed in to change notification settings - Fork 308
2단계 - 수강신청(도메인 모델) #818
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
Open
username0w
wants to merge
28
commits into
next-step:username0w
Choose a base branch
from
username0w:step2
base: username0w
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
2단계 - 수강신청(도메인 모델) #818
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
d0abcf2
docs: 수강 신청 기능 목록 정리
username0w ec941aa
feat: startDate/endDate 검증 구현
username0w 5f35548
feat: 생성 시 기본 상태 PREPARING 설정
username0w b4b63b8
feat: 유료/무료 구분 및 최대 수강인원 검증 구현
username0w 61d5b30
feat: 유료 강의 fee 필드 및 검증 추가
username0w 0ed117d
feat: 상태 기반 수강 신청 가능 여부 구현
username0w 5a09362
feat: 유료 강의 최대 수강 인원 초과 시 수강 불가 검증 추가
username0w f67bd43
feat: 수강 신청 기능 구현
username0w 5901d8f
feat: SessionImage 생성 및 필수 검증 추가
username0w bce1fbd
test: SessionTestBuilder 추가 및 테스트에 적용
username0w 3d04dca
feat: Session에 SessionImage 필드 추가 및 생성자 검증
username0w 3d8f3a0
feat: 수강 기간, 수강 정원, 수강료 정보를 담는 VO 추가
username0w 1de7c10
refactor: Session에 Period, Capacity, SessionPricing 적용
username0w 3151975
feat: Session 관련 불변 정보 SessionInfo 추가
username0w 35191a7
feat: EnrollmentPolicy 인터페이스 및 구현체 추가
username0w 8340a2c
feat: SessionPricing을 Session으로 이동 and SessionInfo 필드 일부 외부 추출, Enrol…
username0w e834e6d
feat: ImageDimension 추가
username0w bbbc5b7
feat: ImageSize 추가
username0w 23c29f0
feat: ImageSize, ImageDimension 적용
username0w 61fd7b1
feat: FileName 추가
username0w cc4028c
feat: FileName 적용
username0w 3d841cf
feat: Enrollment 추가
username0w 9b6e440
feat: Enrollment, Enrollments 추가
username0w 7766878
feat: Enrollment, Enrollments 적용, Capacity unlimited 필드 추가
username0w 6e6c5fd
feat: 사용하지 않는 EnrollmentPolicy 제거
username0w ab7d29e
feat: 정적 팩토리 도입으로 불가능한 도메인 상태 생성 방지
username0w d4b5dd9
feat: Pricing과 Payment 비교 로직 이동
username0w 61df420
refactor: Stream 사용, 예외 메시지 상수화
username0w 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 hidden or 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
This file contains hidden or 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
This file contains hidden or 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,87 @@ | ||
| package nextstep.sessions.domain; | ||
|
|
||
| public class Capacity { | ||
|
|
||
| private static final String ERROR_MAX_CAPACITY_REQUIRED = "유료 강의는 최대 수강인원이 있어야 합니다"; | ||
| private static final String ERROR_ENROLL_COUNT_NEGATIVE = "수강 인원은 0 이상이어야 합니다"; | ||
| private static final String ERROR_ENROLL_COUNT_EXCEED = "수강 인원은 수강 정원을 초과할 수 없습니다"; | ||
| private static final String ERROR_CANNOT_ENROLL = "수강 신청을 할 수 없습니다"; | ||
|
|
||
| private static final int DEFAULT_ENROLL_COUNT = 0; | ||
|
|
||
| private final Integer maxCapacity; | ||
| private final boolean unlimited; | ||
| private final int enrollCount; | ||
|
|
||
|
|
||
| Capacity(Integer maxCapacity, boolean unlimited) { | ||
| this(maxCapacity, unlimited, DEFAULT_ENROLL_COUNT); | ||
| } | ||
|
|
||
| Capacity(Integer maxCapacity, boolean unlimited, int enrollCount) { | ||
| validateMaxCapacity(maxCapacity); | ||
| validateEnrollCount(enrollCount); | ||
| validateEnrollCountWithinCapacity(maxCapacity, enrollCount); | ||
|
|
||
| this.maxCapacity = maxCapacity; | ||
| this.unlimited = unlimited; | ||
| this.enrollCount = enrollCount; | ||
| } | ||
|
|
||
| public static Capacity limited(int maxCapacity) { | ||
| return new Capacity(maxCapacity, false, DEFAULT_ENROLL_COUNT); | ||
| } | ||
|
|
||
| public static Capacity unlimited() { | ||
| return new Capacity(Integer.MAX_VALUE, true, 0); | ||
| } | ||
|
|
||
| public Integer maxCapacity() { | ||
| return maxCapacity; | ||
| } | ||
|
|
||
| public int enrollCount() { | ||
| return enrollCount; | ||
| } | ||
|
|
||
| public boolean canEnroll() { | ||
| return unlimited || enrollCount < maxCapacity; | ||
| } | ||
|
|
||
| public boolean isUnlimited() { | ||
| return unlimited; | ||
| } | ||
|
|
||
| public boolean isFull() { | ||
| return enrollCount >= maxCapacity; | ||
| } | ||
|
|
||
| public boolean hasAvailableSeat() { | ||
| return !isFull(); | ||
| } | ||
|
|
||
| public Capacity increaseEnrollCount() { | ||
| if (!canEnroll()) { | ||
| throw new IllegalArgumentException(ERROR_CANNOT_ENROLL); | ||
| } | ||
| return new Capacity(maxCapacity, unlimited, enrollCount + 1); | ||
| } | ||
|
|
||
| private void validateMaxCapacity(Integer maxCapacity) { | ||
| if (!unlimited && (maxCapacity == null || maxCapacity <= 0)) { | ||
| throw new IllegalArgumentException(ERROR_MAX_CAPACITY_REQUIRED); | ||
| } | ||
| } | ||
|
|
||
| private static void validateEnrollCount(int enrollCount) { | ||
| if (enrollCount < 0) { | ||
| throw new IllegalArgumentException(ERROR_ENROLL_COUNT_NEGATIVE); | ||
| } | ||
| } | ||
|
|
||
| private static void validateEnrollCountWithinCapacity(Integer maxCapacity, int enrollCount) { | ||
| if (maxCapacity != null && enrollCount > maxCapacity) { | ||
| throw new IllegalArgumentException(ERROR_ENROLL_COUNT_EXCEED); | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or 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,56 @@ | ||
| package nextstep.sessions.domain; | ||
|
|
||
| import java.time.LocalDateTime; | ||
| import java.util.Objects; | ||
| import nextstep.payments.domain.Payment; | ||
| import nextstep.users.domain.NsUser; | ||
|
|
||
| public class Enrollment { | ||
|
|
||
| static final String ERROR_USER_PAYMENT_MISMATCH = "결제한 사용자와 신청자가 일치하지 않습니다"; | ||
|
|
||
| private final NsUser user; | ||
| private final Payment payment; | ||
| private final LocalDateTime enrolledAt; | ||
|
|
||
| public Enrollment(NsUser user, Payment payment) { | ||
| validateUserPayMatch(user, payment); | ||
| this.user = user; | ||
| this.payment = payment; | ||
| this.enrolledAt = LocalDateTime.now(); | ||
| } | ||
|
|
||
| public Payment payment() { | ||
| return payment; | ||
| } | ||
|
|
||
| public boolean canPayFor(SessionPricing pricing) { | ||
| return !pricing.isPaid() || payment.isPaidFor(pricing.fee()); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) { | ||
| return true; | ||
| } | ||
| if (o == null || getClass() != o.getClass()) { | ||
| return false; | ||
| } | ||
| Enrollment that = (Enrollment) o; | ||
| return Objects.equals(user, that.user) && Objects.equals(payment, that.payment) | ||
| && Objects.equals(enrolledAt, that.enrolledAt); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(user, payment, enrolledAt); | ||
| } | ||
|
|
||
| private static void validateUserPayMatch(NsUser user, Payment payment) { | ||
| if (payment.isPaidBy(user)) { | ||
| return; | ||
| } | ||
| throw new IllegalArgumentException(ERROR_USER_PAYMENT_MISMATCH); | ||
| } | ||
|
|
||
| } |
This file contains hidden or 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,23 @@ | ||
| package nextstep.sessions.domain; | ||
|
|
||
| import java.util.HashSet; | ||
| import java.util.Set; | ||
|
|
||
| public class Enrollments { | ||
|
|
||
| static final String ERROR_ALREADY_ENROLLED = "이미 등록된 사용자입니다."; | ||
|
|
||
| private final Set<Enrollment> enrollments = new HashSet<>(); | ||
|
|
||
| public void add(Enrollment enrollment) { | ||
| if (enrollments.contains(enrollment)) { | ||
| throw new IllegalArgumentException(ERROR_ALREADY_ENROLLED); | ||
| } | ||
| enrollments.add(enrollment); | ||
| } | ||
|
|
||
| public int size() { | ||
| return enrollments.size(); | ||
| } | ||
| } | ||
|
|
This file contains hidden or 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,27 @@ | ||
| package nextstep.sessions.domain; | ||
|
|
||
| public class FileName { | ||
|
|
||
| static final String ERROR_FILENAME_NOT_EMPTY = "파일명은 빈 값일 수 없습니다"; | ||
| private final String value; | ||
|
|
||
| public FileName(String value) { | ||
| validate(value); | ||
| this.value = value; | ||
| } | ||
|
|
||
| public String value() { | ||
| return value; | ||
| } | ||
|
|
||
| public String extension() { | ||
| return value.substring(value.lastIndexOf('.') + 1); | ||
| } | ||
|
|
||
| private void validate(String fileName) { | ||
| if (fileName == null || fileName.trim().isEmpty()) { | ||
| throw new IllegalArgumentException(ERROR_FILENAME_NOT_EMPTY); | ||
| } | ||
| } | ||
|
|
||
| } |
29 changes: 29 additions & 0 deletions
29
src/main/java/nextstep/sessions/domain/ImageDimension.java
This file contains hidden or 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,29 @@ | ||
| package nextstep.sessions.domain; | ||
|
|
||
| public class ImageDimension { | ||
|
|
||
| private static final int MIN_WIDTH = 300; | ||
| private static final int MIN_HEIGHT = 200; | ||
|
|
||
| private static final String ERROR_MIN_SIZE = "이미지 크기가 최소 조건을 만족하지 않습니다"; | ||
| private static final String ERROR_RATIO = "이미지 비율은 3:2여야 합니다"; | ||
|
|
||
| private final int width; | ||
| private final int height; | ||
|
|
||
| public ImageDimension(int width, int height) { | ||
| validate(width, height); | ||
| this.width = width; | ||
| this.height = height; | ||
| } | ||
|
|
||
| private void validate(int width, int height) { | ||
| if (width < MIN_WIDTH || height < MIN_HEIGHT) { | ||
| throw new IllegalArgumentException(ERROR_MIN_SIZE); | ||
| } | ||
| if (width * 2 != height * 3) { | ||
| throw new IllegalArgumentException(ERROR_RATIO); | ||
| } | ||
| } | ||
|
|
||
| } |
This file contains hidden or 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,24 @@ | ||
| package nextstep.sessions.domain; | ||
|
|
||
| public class ImageSize { | ||
|
|
||
| static final String ERROR_IMAGE_SIZE = "이미지 용량은 1MB 이하여야 합니다"; | ||
| private static final long MAX_SIZE = 1_000_000; | ||
|
|
||
| private final long size; | ||
|
|
||
| public ImageSize(long size) { | ||
| validate(size); | ||
| this.size = size; | ||
| } | ||
|
|
||
| private static void validate(long size) { | ||
| if (size <= 0 || size > MAX_SIZE) { | ||
| throw new IllegalArgumentException(ERROR_IMAGE_SIZE); | ||
| } | ||
| } | ||
|
|
||
| public long value() { | ||
| return size; | ||
| } | ||
| } |
This file contains hidden or 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,22 @@ | ||
| package nextstep.sessions.domain; | ||
|
|
||
| import java.util.Arrays; | ||
|
|
||
| public enum ImageType { | ||
| GIF, JPG, JPEG, PNG, SVG; | ||
|
|
||
| private static final String ERROR_EMPTY_EXT = "확장자가 유효하지 않습니다"; | ||
| private static final String ERROR_UNSUPPORTED_EXT = "지원하지 않는 이미지 형식입니다: "; | ||
|
|
||
| public static ImageType from(String ext) { | ||
| if (ext == null || ext.trim().isEmpty()) { | ||
| throw new IllegalArgumentException(ERROR_EMPTY_EXT); | ||
| } | ||
|
|
||
| return Arrays.stream(ImageType.values()) | ||
| .filter(type -> type.name().equalsIgnoreCase(ext)) | ||
| .findFirst() | ||
| .orElseThrow(() -> new IllegalArgumentException(ERROR_UNSUPPORTED_EXT + ext)); | ||
| } | ||
| } | ||
|
|
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.
db가 아닌 도메인 객체인 만큼 수강생 목록을 가지는 것은 어떨까?
db를 고려해 구현한 것은 아닐까?