diff --git a/md/step4.md b/md/step4.md
new file mode 100644
index 000000000..5e863ca82
--- /dev/null
+++ b/md/step4.md
@@ -0,0 +1,29 @@
+# π 4λ¨κ³ - μκ°μ μ²(μꡬμ¬ν λ³κ²½)
+
+## ν΅μ¬ νμ΅ λͺ©ν
+
+- DB ν
μ΄λΈμ΄ λ³κ²½λ λλ μ€νΈλκΈλ¬ ν¨ν΄μ μ μ©ν΄ μ μ§μ μΈ λ¦¬ν©ν°λ§μ μ°μ΅νλ€.
+ - [μ€νΈλκΈλ¬(κ΅μ΄μ) ν¨ν΄ - λ§ν΄ νμΈλ¬](https://martinfowler.com/bliki/StranglerFigApplication.html)
+ - [μ€νΈλκΈλ¬ 무νκ³Ό ν¨ν΄](https://docs.microsoft.com/ko-kr/azure/architecture/patterns/strangler-fig)
+
+
+
+## λ³κ²½λ κΈ°λ₯ μꡬμ¬ν
+### **κ°μ μκ°μ μ²μ κ°μ μνκ° λͺ¨μ§μ€μΌ λλ§ κ°λ₯νλ€.**
+- [X] κ°μκ° μ§ν μ€μΈ μνμμλ μκ°μ μ²μ΄ κ°λ₯ν΄μΌ νλ€.
+ - κ°μ μ§ν μν(μ€λΉμ€, μ§νμ€, μ’
λ£)μ λͺ¨μ§ μν(λΉλͺ¨μ§μ€, λͺ¨μ§μ€)λ‘ μν κ°μ λΆλ¦¬ν΄μΌ νλ€.
+
+### **κ°μλ κ°μ μ»€λ² μ΄λ―Έμ§ μ 보λ₯Ό κ°μ§λ€.**
+- [X] κ°μλ **νλ μ΄μ**μ μ»€λ² μ΄λ―Έμ§λ₯Ό κ°μ§ μ μλ€.
+
+### κ°μ¬κ° μΉμΈνμ§ μμλ μκ° μ μ²νλ λͺ¨λ μ¬λμ΄ μκ° κ°λ₯νλ€.
+- [ ] μ°μνν
ν¬μ½μ€(무λ£), μ°μνν
ν¬μΊ ν Pro(μ λ£)μ κ°μ΄ μ λ°λ μΈμλ§ μκ° κ°λ₯ν΄μΌ νλ€.
+ - [ ] κ°μ¬λ μκ°μ μ²ν μ¬λ μ€ μ λ°λ μΈμμ λν΄μλ§ μκ° μΉμΈμ΄ κ°λ₯ν΄μΌ νλ€.
+ - [ ] κ°μ¬λ μκ°μ μ²ν μ¬λ μ€ μ λ°λμ§ μμ μ¬λμ μκ°μ μ·¨μν μ μμ΄μΌ νλ€.
+
+
+
+## νλ‘κ·Έλλ° μꡬμ¬ν
+- 리ν©ν°λ§ν λ μ»΄νμΌ μλ¬μ κΈ°μ‘΄μ λ¨μ ν
μ€νΈμ μ€ν¨λ₯Ό μ΅μννλ©΄μ μ μ§μ μΈ λ¦¬ν©ν°λ§μ΄ κ°λ₯νλλ‘ νλ€.
+- DB ν
μ΄λΈμ λ°μ΄ν°κ° μ‘΄μ¬νλ€λ κ°μ νμ 리ν©ν°λ§ν΄μΌ νλ€.
+ - μ¦, κΈ°μ‘΄μ μμΈ λ°μ΄ν°λ₯Ό μ κ±°νμ§ μμ μνλ‘ λ¦¬ν©ν°λ§ ν΄μΌ νλ€.
diff --git a/src/main/java/nextstep/courses/domain/CoverImages.java b/src/main/java/nextstep/courses/domain/CoverImages.java
new file mode 100644
index 000000000..969834ad1
--- /dev/null
+++ b/src/main/java/nextstep/courses/domain/CoverImages.java
@@ -0,0 +1,21 @@
+package nextstep.courses.domain;
+
+import nextstep.courses.exception.EmptyCoverImageException;
+
+import java.util.List;
+
+public class CoverImages {
+
+ private List images;
+
+ public CoverImages(List images) {
+ validateIsNull(images);
+ this.images = images;
+ }
+
+ private void validateIsNull(List images) {
+ if (images == null || images.isEmpty()) {
+ throw new EmptyCoverImageException();
+ }
+ }
+}
diff --git a/src/main/java/nextstep/courses/domain/Period.java b/src/main/java/nextstep/courses/domain/Period.java
index f57b036fb..b5a4d9606 100644
--- a/src/main/java/nextstep/courses/domain/Period.java
+++ b/src/main/java/nextstep/courses/domain/Period.java
@@ -25,10 +25,6 @@ private void validatePeriod(LocalDate startDate, LocalDate endDate) {
}
}
- public boolean isDateWithinRange(LocalDate date) {
- return !date.isBefore(startDate) && !date.isAfter(endDate);
- }
-
public LocalDate startDate() {
return startDate;
}
diff --git a/src/main/java/nextstep/courses/domain/RecruitmentStatus.java b/src/main/java/nextstep/courses/domain/RecruitmentStatus.java
new file mode 100644
index 000000000..c39f26c24
--- /dev/null
+++ b/src/main/java/nextstep/courses/domain/RecruitmentStatus.java
@@ -0,0 +1,27 @@
+package nextstep.courses.domain;
+
+import nextstep.courses.exception.InvalidRecruitmentStatusException;
+
+import java.util.Arrays;
+
+public enum RecruitmentStatus {
+ NOT_RECRUITMENT,
+ RECRUITING;
+
+ private static final RecruitmentStatus[] VALUES = values();
+
+ public static RecruitmentStatus findByName(String name) {
+ return Arrays.stream(VALUES)
+ .filter(status -> status.name().equalsIgnoreCase(name))
+ .findFirst()
+ .orElseThrow(() -> new InvalidRecruitmentStatusException(name));
+ }
+
+ public RecruitmentStatus ofRecruiting() {
+ return RECRUITING;
+ }
+
+ public boolean isRecruiting() {
+ return this == RECRUITING;
+ }
+}
diff --git a/src/main/java/nextstep/courses/domain/Session.java b/src/main/java/nextstep/courses/domain/Session.java
index 2a12b369b..69e826883 100644
--- a/src/main/java/nextstep/courses/domain/Session.java
+++ b/src/main/java/nextstep/courses/domain/Session.java
@@ -1,8 +1,6 @@
package nextstep.courses.domain;
import nextstep.courses.exception.InvalidSessionException;
-import nextstep.courses.exception.NotOpenSessionException;
-import nextstep.courses.exception.OutOfSessionException;
import nextstep.payments.domain.Payment;
import java.time.LocalDate;
@@ -13,39 +11,39 @@ public class Session extends BaseEntity {
private final Long id;
private final Long courseId;
private final SessionType type;
- private final CoverImage coverImage;
+ private final CoverImages coverImages;
private final Period period;
- private Status status;
+ private final Status status;
private final Students students;
private final PaidCondition paidCondition;
- public static Session ofFree(Long id, Long courseId, CoverImage coverImage, LocalDate startDate, LocalDate endDate) {
- return new Session(id, courseId, SessionType.FREE, coverImage, new Period(startDate, endDate), Status.NOT_OPEN, 0, 0L, LocalDateTime.now(), null);
+ public static Session ofFree(Long id, Long courseId, CoverImages coverImages, LocalDate startDate, LocalDate endDate) {
+ return new Session(id, courseId, SessionType.FREE, coverImages, new Period(startDate, endDate), new Status(LocalDate.now(), startDate, endDate), 0, 0L, LocalDateTime.now(), null);
}
- public static Session ofPaid(Long id, Long courseId, CoverImage coverImage, LocalDate startDate, LocalDate endDate, int maxStudents, Long fee) {
- return new Session(id, courseId, SessionType.PAID, coverImage, new Period(startDate, endDate), Status.NOT_OPEN, maxStudents, fee, LocalDateTime.now(), null);
+ public static Session ofPaid(Long id, Long courseId, CoverImages coverImages, LocalDate startDate, LocalDate endDate, int maxStudents, Long fee) {
+ return new Session(id, courseId, SessionType.PAID, coverImages, new Period(startDate, endDate), new Status(LocalDate.now(), startDate, endDate), maxStudents, fee, LocalDateTime.now(), null);
}
- public static Session of(Long id, Long courseId, SessionType type, CoverImage coverImage, Status status, LocalDate startDate, LocalDate endDate, int maxStudents, Long fee, LocalDateTime createdAt, LocalDateTime updatedAt) {
- return new Session(id, courseId, type, coverImage, new Period(startDate, endDate), status, maxStudents, fee, createdAt, updatedAt);
+ public static Session of(Long id, Long courseId, SessionType type, CoverImages coverImages, RecruitmentStatus recruitmentStatus, LocalDate startDate, LocalDate endDate, int maxStudents, Long fee, LocalDateTime createdAt, LocalDateTime updatedAt) {
+ return new Session(id, courseId, type, coverImages, new Period(startDate, endDate), new Status(LocalDate.now(), startDate, endDate, recruitmentStatus), maxStudents, fee, createdAt, updatedAt);
}
- private Session(Long id, Long courseId, SessionType type, CoverImage coverImage, Period period, Status status, int maxStudents, Long fee, LocalDateTime createdAt, LocalDateTime updatedAt) {
+ private Session(Long id, Long courseId, SessionType type, CoverImages coverImages, Period period, Status status, int maxStudents, Long fee, LocalDateTime createdAt, LocalDateTime updatedAt) {
super(createdAt, updatedAt);
- validateNotNull(id, coverImage, period);
+ validateNotNull(id, coverImages, period);
this.id = id;
this.courseId = courseId;
this.type = type;
- this.coverImage = coverImage;
+ this.coverImages = coverImages;
this.period = period;
this.status = status;
this.students = new Students();
this.paidCondition = new PaidCondition(maxStudents, fee);
}
- private void validateNotNull(Long id, CoverImage coverImage, Period period) {
- if (id == null || coverImage == null || period == null) {
+ private void validateNotNull(Long id, CoverImages coverImages, Period period) {
+ if (id == null || coverImages == null || period == null) {
throw new InvalidSessionException();
}
}
@@ -59,20 +57,11 @@ public void register(Payment payment) {
}
protected void validateStatus() {
- if (!status.isOpen()) {
- throw new NotOpenSessionException();
- }
- }
-
- public void openSession() {
- if (!period.isDateWithinRange(LocalDate.now())) {
- throw new OutOfSessionException();
- }
- changeStatusOpen();
+ this.status.validate();
}
- private void changeStatusOpen() {
- this.status = status.ofOpen();
+ public void startRecruiting() {
+ this.status.startRecruiting();
}
public Long id() {
@@ -83,16 +72,16 @@ public Long courseId() {
return courseId;
}
- public Long imageId() {
- return coverImage.getId();
- }
-
public String type() {
return type.name();
}
- public String status() {
- return status.name();
+ public String sessionStatus() {
+ return status.sessionStatus();
+ }
+
+ public String recruitmentStatus() {
+ return status.recruitmentStatus();
}
public LocalDate startDate() {
@@ -115,8 +104,9 @@ public Long fee() {
public String toString() {
return "Session{" +
"id=" + id +
+ ", courseId=" + courseId +
", type=" + type +
- ", coverImage=" + coverImage +
+ ", coverImages=" + coverImages +
", period=" + period +
", status=" + status +
", students=" + students +
diff --git a/src/main/java/nextstep/courses/domain/SessionStatus.java b/src/main/java/nextstep/courses/domain/SessionStatus.java
new file mode 100644
index 000000000..8138217b0
--- /dev/null
+++ b/src/main/java/nextstep/courses/domain/SessionStatus.java
@@ -0,0 +1,25 @@
+package nextstep.courses.domain;
+
+import java.time.LocalDate;
+
+public enum SessionStatus {
+ PREPARING,
+ IN_PROGRESS,
+ COMPLETED;
+
+ public static SessionStatus of(LocalDate now, LocalDate startDate, LocalDate endDate) {
+ if (now.isBefore(startDate)) {
+ return PREPARING;
+ }
+
+ if (now.isAfter(startDate) && now.isBefore(endDate)) {
+ return IN_PROGRESS;
+ }
+
+ return COMPLETED;
+ }
+
+ public boolean isInProgress() {
+ return this == IN_PROGRESS;
+ }
+}
diff --git a/src/main/java/nextstep/courses/domain/Status.java b/src/main/java/nextstep/courses/domain/Status.java
index fec47173b..578e80a91 100644
--- a/src/main/java/nextstep/courses/domain/Status.java
+++ b/src/main/java/nextstep/courses/domain/Status.java
@@ -1,27 +1,42 @@
package nextstep.courses.domain;
-import nextstep.courses.exception.InvalidSessionStatusException;
+import nextstep.courses.exception.NotOpenSessionException;
-import java.util.Arrays;
+import java.time.LocalDate;
-public enum Status {
- NOT_OPEN,
- OPEN,
- CLOSED;
+public class Status {
+ private SessionStatus sessionStatus;
+ private RecruitmentStatus recruitmentStatus;
- public Status ofOpen() {
- return OPEN;
+ public Status(LocalDate now, LocalDate startDate, LocalDate endDate) {
+ this(SessionStatus.of(now, startDate, endDate), RecruitmentStatus.NOT_RECRUITMENT);
}
- public boolean isOpen() {
- return this == OPEN;
+ public Status(LocalDate now, LocalDate startDate, LocalDate endDate, RecruitmentStatus recruitmentStatus) {
+ this(SessionStatus.of(now, startDate, endDate), recruitmentStatus);
}
- public static Status findByName(String name) {
- return Arrays.stream(values())
- .filter(status -> status.name().equalsIgnoreCase(name))
- .findFirst()
- .orElseThrow(() -> new InvalidSessionStatusException(name));
+ public Status(SessionStatus sessionStatus, RecruitmentStatus recruitmentStatus) {
+ this.sessionStatus = sessionStatus;
+ this.recruitmentStatus = recruitmentStatus;
+ }
+
+ public void validate() {
+ if (!sessionStatus.isInProgress() && !recruitmentStatus.isRecruiting()) {
+ throw new NotOpenSessionException();
+ }
+ }
+
+ public void startRecruiting() {
+ this.recruitmentStatus = recruitmentStatus.ofRecruiting();
+ }
+
+ public String sessionStatus() {
+ return this.sessionStatus.name();
+ }
+
+ public String recruitmentStatus() {
+ return this.recruitmentStatus.name();
}
}
diff --git a/src/main/java/nextstep/courses/exception/EmptyCoverImageException.java b/src/main/java/nextstep/courses/exception/EmptyCoverImageException.java
new file mode 100644
index 000000000..49d5a79b8
--- /dev/null
+++ b/src/main/java/nextstep/courses/exception/EmptyCoverImageException.java
@@ -0,0 +1,8 @@
+package nextstep.courses.exception;
+
+public class EmptyCoverImageException extends RuntimeException {
+
+ public EmptyCoverImageException() {
+ super("κ°μλ νλ μ΄μμ μ»€λ² μ΄λ―Έμ§λ₯Ό κ°μ ΈμΌ ν©λλ€.");
+ }
+}
diff --git a/src/main/java/nextstep/courses/exception/InvalidRecruitmentStatusException.java b/src/main/java/nextstep/courses/exception/InvalidRecruitmentStatusException.java
new file mode 100644
index 000000000..10067cd5a
--- /dev/null
+++ b/src/main/java/nextstep/courses/exception/InvalidRecruitmentStatusException.java
@@ -0,0 +1,8 @@
+package nextstep.courses.exception;
+
+public class InvalidRecruitmentStatusException extends RuntimeException {
+
+ public InvalidRecruitmentStatusException(String code) {
+ super("μ‘΄μ¬νμ§ μλ κ°μ λͺ¨μ§ μνμ
λλ€." + code);
+ }
+}
diff --git a/src/main/java/nextstep/courses/exception/InvalidSessionStatusException.java b/src/main/java/nextstep/courses/exception/InvalidSessionStatusException.java
deleted file mode 100644
index 2411415f8..000000000
--- a/src/main/java/nextstep/courses/exception/InvalidSessionStatusException.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package nextstep.courses.exception;
-
-public class InvalidSessionStatusException extends RuntimeException {
-
- public InvalidSessionStatusException(String code) {
- super("μ‘΄μ¬νμ§ μλ κ°μ μνμ
λλ€." + code);
- }
-}
diff --git a/src/main/java/nextstep/courses/exception/NotOpenSessionException.java b/src/main/java/nextstep/courses/exception/NotOpenSessionException.java
index acad19812..68ada8d5a 100644
--- a/src/main/java/nextstep/courses/exception/NotOpenSessionException.java
+++ b/src/main/java/nextstep/courses/exception/NotOpenSessionException.java
@@ -2,6 +2,6 @@
public class NotOpenSessionException extends RuntimeException {
public NotOpenSessionException() {
- super("λͺ¨μ§ μ€μΈ κ°μκ° μλλλ€.");
+ super("μ§ν μ€μ΄κ±°λ λͺ¨μ§ μ€μΈ κ°μκ° μλλλ€.");
}
}
diff --git a/src/main/java/nextstep/courses/infrastructure/JdbcCoverImageRepository.java b/src/main/java/nextstep/courses/infrastructure/JdbcCoverImageRepository.java
index 3210c0491..aaa84a932 100644
--- a/src/main/java/nextstep/courses/infrastructure/JdbcCoverImageRepository.java
+++ b/src/main/java/nextstep/courses/infrastructure/JdbcCoverImageRepository.java
@@ -8,6 +8,7 @@
import java.sql.Timestamp;
import java.time.LocalDateTime;
+import java.util.List;
@Repository("coverImageRepository")
public class JdbcCoverImageRepository implements CoverImageRepository {
@@ -19,23 +20,33 @@ public JdbcCoverImageRepository(JdbcOperations jdbcTemplate) {
}
@Override
- public int save(CoverImage image) {
- String sql = "insert into cover_image (id, size, extension, width, height, created_at) values(?, ?, ?, ?, ?, ?)";
- return jdbcTemplate.update(sql, image.getId(), image.getSize(), image.getExtension(), image.getWidth(), image.getHeight(), image.getCreatedAt());
+ public int save(CoverImage image, Long sessionId) {
+ String sql = "insert into cover_image (id, session_id, size, extension, width, height, created_at) values(?, ?, ?, ?, ?, ?, ?)";
+ return jdbcTemplate.update(sql, image.getId(), sessionId, image.getSize(), image.getExtension(), image.getWidth(), image.getHeight(), image.getCreatedAt());
}
@Override
public CoverImage findById(Long id) {
- String sql = "select id, size, extension, width, height, created_at, updated_at from cover_image where id = ?";
+ String sql = "select id, session_id, size, extension, width, height, created_at, updated_at from cover_image where id = ?";
+ return jdbcTemplate.queryForObject(sql, rowMapper(), id);
+ }
+
+ @Override
+ public List findAllBySessionId(Long id) {
+ String sql = "select id, session_id, size, extension, width, height, created_at, updated_at from cover_image where session_id = ?";
+ return jdbcTemplate.query(sql, rowMapper(), id);
+ }
+
+ private RowMapper rowMapper() {
RowMapper rowMapper = (rs, rowNum) -> new CoverImage(
rs.getLong(1),
- rs.getLong(2),
- rs.getString(3),
- rs.getInt(4),
+ rs.getLong(3),
+ rs.getString(4),
rs.getInt(5),
- toLocalDateTime(rs.getTimestamp(6)),
- toLocalDateTime(rs.getTimestamp(7)));
- return jdbcTemplate.queryForObject(sql, rowMapper, id);
+ rs.getInt(6),
+ toLocalDateTime(rs.getTimestamp(7)),
+ toLocalDateTime(rs.getTimestamp(8)));
+ return rowMapper;
}
private LocalDateTime toLocalDateTime(Timestamp timestamp) {
diff --git a/src/main/java/nextstep/courses/infrastructure/JdbcSessionRepository.java b/src/main/java/nextstep/courses/infrastructure/JdbcSessionRepository.java
index 755df2281..cd6bb4add 100644
--- a/src/main/java/nextstep/courses/infrastructure/JdbcSessionRepository.java
+++ b/src/main/java/nextstep/courses/infrastructure/JdbcSessionRepository.java
@@ -1,9 +1,9 @@
package nextstep.courses.infrastructure;
-import nextstep.courses.domain.CoverImage;
+import nextstep.courses.domain.CoverImages;
+import nextstep.courses.domain.RecruitmentStatus;
import nextstep.courses.domain.Session;
import nextstep.courses.domain.SessionType;
-import nextstep.courses.domain.Status;
import nextstep.courses.repository.CoverImageRepository;
import nextstep.courses.repository.SessionRepository;
import org.springframework.jdbc.core.JdbcOperations;
@@ -29,25 +29,25 @@ public JdbcSessionRepository(JdbcOperations jdbcTemplate) {
@Override
public int save(Session session) {
- String sql = "insert into session (id, course_id, image_id, type, status, start_date, end_date, max_students, fee, created_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
- return jdbcTemplate.update(sql, session.id(), session.courseId(), session.imageId(), session.type(), session.status(), session.startDate(), session.endDate(), session.maxStudents(), session.fee(), session.getCreatedAt());
+ String sql = "insert into session (id, course_id, type, recruitment_status, start_date, end_date, max_students, fee, created_at) values (?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ return jdbcTemplate.update(sql, session.id(), session.courseId(), session.type(), session.recruitmentStatus(), session.startDate(), session.endDate(), session.maxStudents(), session.fee(), session.getCreatedAt());
}
@Override
public Session findById(Long id) {
- String sql = "select id, course_id, type, image_id, status, start_date, end_date, max_students, fee, created_at, updated_at from session where id = ?";
+ String sql = "select id, course_id, type, recruitment_status, start_date, end_date, max_students, fee, created_at, updated_at from session where id = ?";
RowMapper rowMapper = (rs, rowNum) -> Session.of(
rs.getLong(1),
rs.getLong(2),
SessionType.findByCode(rs.getString(3)),
- coverImage(rs.getLong(4)),
- Status.findByName(rs.getString(5)),
+ coverImages(id),
+ RecruitmentStatus.findByName(rs.getString(4)),
+ toLocalDate(rs.getDate(5)),
toLocalDate(rs.getDate(6)),
- toLocalDate(rs.getDate(7)),
- rs.getInt(8),
- rs.getLong(9),
- toLocalDateTime(rs.getTimestamp(10)),
- toLocalDateTime(rs.getTimestamp(11)));
+ rs.getInt(7),
+ rs.getLong(8),
+ toLocalDateTime(rs.getTimestamp(9)),
+ toLocalDateTime(rs.getTimestamp(10)));
return jdbcTemplate.queryForObject(sql, rowMapper, id);
}
@@ -66,7 +66,7 @@ private LocalDate toLocalDate(Date date) {
return date.toLocalDate();
}
- private CoverImage coverImage(Long id) {
- return coverImageRepository.findById(id);
+ private CoverImages coverImages(Long id) {
+ return new CoverImages(coverImageRepository.findAllBySessionId(id));
}
}
diff --git a/src/main/java/nextstep/courses/infrastructure/JdbcStudentsRepository.java b/src/main/java/nextstep/courses/infrastructure/JdbcStudentsRepository.java
index 147c958cb..eecc3c403 100644
--- a/src/main/java/nextstep/courses/infrastructure/JdbcStudentsRepository.java
+++ b/src/main/java/nextstep/courses/infrastructure/JdbcStudentsRepository.java
@@ -5,8 +5,12 @@
import nextstep.users.domain.NsUser;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.RowMapper;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
+import java.sql.PreparedStatement;
+import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Set;
@@ -20,22 +24,40 @@ public JdbcStudentsRepository(JdbcOperations jdbcTemplate) {
}
@Override
- public int save(Long id, Long sessionId) {
+ public Long save(Long id, Long sessionId) {
String sql = "insert into students (session_id, user_id, created_at) values (?, ?, ?)";
- return jdbcTemplate.update(sql, sessionId, id, LocalDateTime.now());
+ KeyHolder keyHolder = new GeneratedKeyHolder();
+ jdbcTemplate.update(connection -> {
+ PreparedStatement ps = connection.prepareStatement(sql, new String[]{"id"});
+ ps.setLong(1, sessionId);
+ ps.setLong(2, id);
+ ps.setTimestamp(3, Timestamp.valueOf(LocalDateTime.now()));
+ return ps;
+ }, keyHolder);
+
+ return keyHolder.getKey().longValue();
}
@Override
public Students findBySessionId(Long id) {
- String sql = "select ns.id, ns.user_id, ns.password, ns.name, ns.email from students st inner join ns_user ns where st.user_id = ns.id and st.session_id = ?";
+ String sql = "select ns.id, ns.user_id, ns.password, ns.name, ns.email, ns.created_at, ns.updated_at from students st inner join ns_user ns where st.user_id = ns.id and st.session_id = ?";
RowMapper rowMapper = (rs, rowNum) -> new NsUser(
rs.getLong(1),
rs.getString(2),
rs.getString(3),
rs.getString(4),
- rs.getString(5)
+ rs.getString(5),
+ toLocalDateTime(rs.getTimestamp(6)),
+ toLocalDateTime(rs.getTimestamp(7))
);
return new Students(Set.of(jdbcTemplate.queryForObject(sql, rowMapper, id)));
}
+
+ private LocalDateTime toLocalDateTime(Timestamp timestamp) {
+ if (timestamp == null) {
+ return null;
+ }
+ return timestamp.toLocalDateTime();
+ }
}
diff --git a/src/main/java/nextstep/courses/repository/CoverImageRepository.java b/src/main/java/nextstep/courses/repository/CoverImageRepository.java
index 44948543c..7473f5c99 100644
--- a/src/main/java/nextstep/courses/repository/CoverImageRepository.java
+++ b/src/main/java/nextstep/courses/repository/CoverImageRepository.java
@@ -2,8 +2,12 @@
import nextstep.courses.domain.CoverImage;
+import java.util.List;
+
public interface CoverImageRepository {
- int save(CoverImage coverImage);
+ int save(CoverImage coverImage, Long sessionId);
CoverImage findById(Long id);
+
+ List findAllBySessionId(Long id);
}
diff --git a/src/main/java/nextstep/courses/repository/StudentsRepository.java b/src/main/java/nextstep/courses/repository/StudentsRepository.java
index c05268630..77d5edd63 100644
--- a/src/main/java/nextstep/courses/repository/StudentsRepository.java
+++ b/src/main/java/nextstep/courses/repository/StudentsRepository.java
@@ -4,7 +4,7 @@
public interface StudentsRepository {
- int save(Long id, Long sessionId);
+ Long save(Long id, Long sessionId);
Students findBySessionId(Long id);
}
diff --git a/src/main/java/nextstep/courses/service/CoverImageService.java b/src/main/java/nextstep/courses/service/CoverImageService.java
new file mode 100644
index 000000000..31488b613
--- /dev/null
+++ b/src/main/java/nextstep/courses/service/CoverImageService.java
@@ -0,0 +1,18 @@
+package nextstep.courses.service;
+
+import nextstep.courses.domain.CoverImage;
+import nextstep.courses.repository.CoverImageRepository;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+
+public class CoverImageService {
+
+ @Resource(name = "coverImageRepository")
+ private CoverImageRepository coverImageRepository;
+
+ @Transactional
+ public void createCoverImage(CoverImage image, Long sessionId) {
+ coverImageRepository.save(image, sessionId);
+ }
+}
diff --git a/src/main/java/nextstep/users/domain/NsUser.java b/src/main/java/nextstep/users/domain/NsUser.java
index 25050fee3..91c4d8289 100755
--- a/src/main/java/nextstep/users/domain/NsUser.java
+++ b/src/main/java/nextstep/users/domain/NsUser.java
@@ -124,14 +124,13 @@ public boolean isGuestUser() {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- if (!super.equals(o)) return false;
NsUser nsUser = (NsUser) o;
- return Objects.equals(id, nsUser.id) && Objects.equals(userId, nsUser.userId) && Objects.equals(password, nsUser.password) && Objects.equals(name, nsUser.name) && Objects.equals(email, nsUser.email);
+ return id != null & Objects.equals(id, nsUser.id);
}
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), id, userId, password, name, email);
+ return id != null ? id.intValue() : 0;
}
@Override
diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql
index 0d92f4161..118092d41 100644
--- a/src/main/resources/data.sql
+++ b/src/main/resources/data.sql
@@ -11,8 +11,9 @@ INSERT INTO question (id, writer_id, title, contents, created_at, deleted) VALUE
INSERT INTO course (id, title, creator_id, created_at) VALUES (2, 'JPA νμ©νΈ1', 2, CURRENT_TIMESTAMP());
-INSERT INTO cover_image (id, size, extension, width, height, created_at) VALUES (2, 1, 'jpg', 300, 200, CURRENT_TIMESTAMP());
-
-INSERT INTO session (id, course_id, image_id, type, status, start_date, end_date, max_students, fee, created_at) VALUES (2, 2, 2, 'FREE', 'NOT_OPEN', '2023-12-01', '2023-12-31', 0, 0, CURRENT_TIMESTAMP());
-INSERT INTO session (id, course_id, image_id, type, status, start_date, end_date, max_students, fee, created_at) VALUES (3, 2, 2, 'PAID', 'NOT_OPEN', '2023-12-01', '2023-12-31', 30, 20000, CURRENT_TIMESTAMP());
+INSERT INTO cover_image (id, session_id, size, extension, width, height, created_at) VALUES (2, 3, 1, 'jpg', 300, 200, CURRENT_TIMESTAMP());
+INSERT INTO cover_image (id, session_id, size, extension, width, height, created_at) VALUES (3, 2, 1, 'jpg', 300, 200, CURRENT_TIMESTAMP());
+INSERT INTO cover_image (id, session_id, size, extension, width, height, created_at) VALUES (4, 2, 1, 'jpg', 300, 200, CURRENT_TIMESTAMP());
+INSERT INTO session (id, course_id, type, recruitment_status, start_date, end_date, max_students, fee, created_at) VALUES (2, 2, 'FREE', 'NOT_RECRUITMENT', '2023-12-01', '2023-12-31', 0, 0, CURRENT_TIMESTAMP());
+INSERT INTO session (id, course_id, type, recruitment_status, start_date, end_date, max_students, fee, created_at) VALUES (3, 2, 'PAID', 'NOT_RECRUITMENT', '2023-12-01', '2023-12-31', 30, 20000, CURRENT_TIMESTAMP());
diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql
index 4e0d8e4fb..0b9580c0d 100644
--- a/src/main/resources/schema.sql
+++ b/src/main/resources/schema.sql
@@ -51,6 +51,7 @@ create table delete_history (
create table cover_image (
id bigint not null,
+ session_id bigint not null,
size double not null,
extension varchar(10) not null,
width int not null,
@@ -63,9 +64,8 @@ create table cover_image (
create table session (
id bigint not null,
course_id bigint not null,
- image_id bigint not null,
type varchar(10) not null,
- status varchar(10) not null,
+ recruitment_status varchar(30) not null,
start_date timestamp not null,
end_date timestamp not null,
max_students int,
diff --git a/src/test/java/nextstep/courses/domain/CourseTest.java b/src/test/java/nextstep/courses/domain/CourseTest.java
index 24460c689..d6f5c34ed 100644
--- a/src/test/java/nextstep/courses/domain/CourseTest.java
+++ b/src/test/java/nextstep/courses/domain/CourseTest.java
@@ -4,6 +4,7 @@
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
+import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -15,7 +16,7 @@ void add_session() {
Course course = new Course(0L, "TDD, ν΄λ¦° μ½λ with Java 17κΈ°", 1L);
CoverImage coverImage = new CoverImage(1, "jpg", 300, 200);
LocalDate now = LocalDate.now();
- Session session = Session.ofFree(0L, 1L, coverImage, now, now);
+ Session session = Session.ofFree(0L, 1L, new CoverImages(List.of(coverImage)), now, now);
course.addSession(session);
diff --git a/src/test/java/nextstep/courses/domain/SessionStatusTest.java b/src/test/java/nextstep/courses/domain/SessionStatusTest.java
new file mode 100644
index 000000000..f7909fb68
--- /dev/null
+++ b/src/test/java/nextstep/courses/domain/SessionStatusTest.java
@@ -0,0 +1,24 @@
+package nextstep.courses.domain;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.time.LocalDate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+class SessionStatusTest {
+
+ @Test
+ @DisplayName("μ€λ λ μ§μ λ§λ μ€λΉμ€, μ§νμ€, μ’
λ£λ₯Ό λ°ννλ€.")
+ void create() {
+ SessionStatus preparing = SessionStatus.of(LocalDate.now(), LocalDate.of(2023, 12, 15), LocalDate.of(2023, 12, 31));
+ assertThat(preparing).isEqualTo(SessionStatus.PREPARING);
+
+ SessionStatus inProgress = SessionStatus.of(LocalDate.now(), LocalDate.of(2023, 12, 1), LocalDate.of(2023, 12, 31));
+ assertThat(inProgress).isEqualTo(SessionStatus.IN_PROGRESS);
+
+ SessionStatus completed = SessionStatus.of(LocalDate.now(), LocalDate.of(2023, 12, 1), LocalDate.of(2023, 12, 5));
+ assertThat(completed).isEqualTo(SessionStatus.COMPLETED);
+ }
+}
diff --git a/src/test/java/nextstep/courses/domain/SessionTest.java b/src/test/java/nextstep/courses/domain/SessionTest.java
index f2b8fa35c..75a7637d3 100644
--- a/src/test/java/nextstep/courses/domain/SessionTest.java
+++ b/src/test/java/nextstep/courses/domain/SessionTest.java
@@ -7,35 +7,36 @@
import org.junit.jupiter.api.Test;
import java.time.LocalDate;
+import java.util.List;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.assertj.core.api.Assertions.*;
class SessionTest {
private static final LocalDate START_DATE = LocalDate.of(2023, 12, 1);
private static final LocalDate END_DATE = LocalDate.of(2023, 12, 31);
- @Test
- @DisplayName("λ¬΄λ£ κ°μ μκ° μ μ² μ κ°μ μνκ° λͺ¨μ§μ€μ΄ μλλ©΄ μμΈλ₯Ό λμ§λ€.")
- void register_status_check() {
- Session freeSession = Session.ofFree(1L, 2L, coverImage(), START_DATE, END_DATE);
- assertThatThrownBy(() -> freeSession.register(Payment.ofFree(1L, NsUserTest.JAVAJIGI)))
- .isInstanceOf(NotOpenSessionException.class);
- }
-
- @Test
- @DisplayName("κ°μ μνλ₯Ό λͺ¨μ§μ€μΌλ‘ λ³κ²½ μ νμ¬ λ μ§κ° κ°μ κΈ°κ°μ μνμ§ μμΌλ©΄ μμΈλ₯Ό λμ§λ€.")
- void register_open() {
- Session session = Session.ofFree(1L, 2L, coverImage(), START_DATE, LocalDate.of(2023, 12, 2));
- assertThatThrownBy(() -> session.openSession())
- .isInstanceOf(OutOfSessionException.class);
- }
+// @Test
+// @DisplayName("λ¬΄λ£ κ°μ μκ° μ μ² μ κ°μ μνκ° λͺ¨μ§μ€μ΄ μλλ©΄ μμΈλ₯Ό λμ§λ€.")
+// void register_status_check() {
+// Session freeSession = Session.ofFree(1L, 2L, coverImages(), START_DATE, END_DATE);
+// assertThatThrownBy(() -> freeSession.register(Payment.ofFree(1L, NsUserTest.JAVAJIGI)))
+// .isInstanceOf(NotOpenSessionException.class);
+// }
+
+// @Test
+// @DisplayName("κ°μ μνλ₯Ό λͺ¨μ§μ€μΌλ‘ λ³κ²½ μ νμ¬ λ μ§κ° κ°μ κΈ°κ°μ μνμ§ μμΌλ©΄ μμΈλ₯Ό λμ§λ€.")
+// void register_open() {
+// Session session = Session.ofFree(1L, 2L, coverImages(), START_DATE, LocalDate.of(2023, 12, 2));
+// assertThatThrownBy(() -> session.startRecruiting())
+// .isInstanceOf(OutOfSessionException.class);
+// }
@Test
@DisplayName("μ λ£ κ°μ μκ° μ μ² μ μ΅λ μκ° μΈμμ μ΄κ³Όνλ©΄ μμΈλ₯Ό λμ§λ€.")
void register_over_students() {
- Session paidSession = Session.ofPaid(1L, 2L, coverImage(), START_DATE, END_DATE, 1, 10_000L);
- paidSession.openSession();
+ Session paidSession = Session.ofPaid(1L, 2L, coverImages(), START_DATE, END_DATE, 1, 10_000L);
+ paidSession.startRecruiting();
paidSession.register(Payment.ofPaid(1L, 1L, NsUserTest.JAVAJIGI, 10_000L));
@@ -46,8 +47,8 @@ void register_over_students() {
@Test
@DisplayName("μ λ£ κ°μ μκ° μ μ² μ κ²°μ κΈμ‘κ³Ό μκ°λ£κ° μΌμΉνλμ§ νμΈνμ§ μμΌλ©΄ μμΈλ₯Ό λμ§λ€.")
void session_fee_test() {
- Session paidSession = Session.ofPaid(1L, 2L, coverImage(), START_DATE, END_DATE, 1, 10_000L);
- paidSession.openSession();
+ Session paidSession = Session.ofPaid(1L, 2L, coverImages(), START_DATE, END_DATE, 1, 10_000L);
+ paidSession.startRecruiting();
assertThatThrownBy(() -> paidSession.register(Payment.ofPaid(2L, 1L, NsUserTest.SANJIGI, 8_000L)))
.isInstanceOf(PaymentMismatchException.class);
@@ -56,15 +57,15 @@ void session_fee_test() {
@Test
@DisplayName("κ°μ μμ± μ κ²°μ κΈμ‘κ³Ό μκ°λ£κ° μμλ©΄ μμΈλ₯Ό λμ§λ€.")
void session_paid_condition_null() {
- assertThatThrownBy(() -> Session.ofPaid(1L, 2L, coverImage(), START_DATE, END_DATE, -1, -1L))
+ assertThatThrownBy(() -> Session.ofPaid(1L, 2L, coverImages(), START_DATE, END_DATE, -1, -1L))
.isInstanceOf(NegativePaidConditionException.class);
}
@Test
@DisplayName("μ€λ³΅ μκ° μ μ² μ μμΈλ₯Ό λμ§λ€.")
void duplicate_register() {
- Session paidSession = Session.ofPaid(1L, 2L, coverImage(), START_DATE, END_DATE, 2, 10_000L);
- paidSession.openSession();
+ Session paidSession = Session.ofPaid(1L, 2L, coverImages(), START_DATE, END_DATE, 2, 10_000L);
+ paidSession.startRecruiting();
paidSession.register(Payment.ofPaid(1L, 1L, NsUserTest.SANJIGI, 10_000L));
@@ -72,7 +73,30 @@ void duplicate_register() {
.isInstanceOf(DuplicateStudentsException.class);
}
- private static CoverImage coverImage() {
- return new CoverImage(1, "gif", 300, 200);
+ @Test
+ @DisplayName("κ°μ μμ± μ μ΄λ―Έμ§κ° μμΌλ©΄ μμΈλ₯Ό λμ§λ€.")
+ void empty_images() {
+ assertThatThrownBy(() -> Session.ofPaid(1L, 2L, new CoverImages(null), START_DATE, END_DATE, 1, 10_000L))
+ .isInstanceOf(EmptyCoverImageException.class);
+ }
+
+ @Test
+ @DisplayName("κ°μ μμ± μ κΈ°κ° λ΄λ©΄ μνκ° μ€λΉμ€μ΄κ³ λͺ¨μ§ μ μ΄λ€.")
+ void session_status() {
+ Session session = Session.ofPaid(1L, 2L, coverImages(), START_DATE, END_DATE, 1, 10_000L);
+ assertThat(session.sessionStatus()).isEqualTo(SessionStatus.IN_PROGRESS.name());
+ assertThat(session.recruitmentStatus()).isEqualTo(RecruitmentStatus.NOT_RECRUITMENT.name());
+ }
+
+ @Test
+ @DisplayName("κ°μ μνκ° λͺ¨μ§μ€μ΄ μλμ΄λ μ§ν μ€μ΄λ©΄ μκ°μ μ²μ΄ κ°λ₯νλ€.")
+ void can_register_not_recruitment() {
+ Session freeSession = Session.ofFree(1L, 2L, coverImages(), START_DATE, END_DATE);
+ assertThatCode(() -> freeSession.register(Payment.ofFree(1L, NsUserTest.JAVAJIGI)))
+ .doesNotThrowAnyException();
+ }
+
+ private static CoverImages coverImages() {
+ return new CoverImages(List.of(new CoverImage(1, "gif", 300, 200)));
}
}
diff --git a/src/test/java/nextstep/courses/infrastructure/CoverImageRepositoryTest.java b/src/test/java/nextstep/courses/infrastructure/CoverImageRepositoryTest.java
index c3d3e8cac..4589f3f51 100644
--- a/src/test/java/nextstep/courses/infrastructure/CoverImageRepositoryTest.java
+++ b/src/test/java/nextstep/courses/infrastructure/CoverImageRepositoryTest.java
@@ -10,6 +10,8 @@
import org.springframework.boot.test.autoconfigure.jdbc.JdbcTest;
import org.springframework.jdbc.core.JdbcTemplate;
+import java.util.List;
+
import static org.assertj.core.api.Assertions.assertThat;
@JdbcTest
@@ -30,7 +32,7 @@ void setUp() {
@Test
void crud() {
CoverImage image = new CoverImage(1, "jpg", 300, 200);
- int count = coverImageRepository.save(image);
+ int count = coverImageRepository.save(image, 2L);
assertThat(count).isEqualTo(1);
CoverImage savedImage = coverImageRepository.findById(1L);
assertThat(savedImage.getId()).isEqualTo(image.getId());
@@ -41,4 +43,11 @@ void crud() {
void find() {
assertThat(coverImageRepository.findById(2L).getId()).isEqualTo(2L);
}
+
+ @Test
+ void findAllBySessionId() {
+ List images = coverImageRepository.findAllBySessionId(2L);
+ assertThat(images.get(0).getId()).isEqualTo(3L);
+ assertThat(images.get(1).getId()).isEqualTo(4L);
+ }
}
diff --git a/src/test/java/nextstep/courses/infrastructure/SessionRepositoryTest.java b/src/test/java/nextstep/courses/infrastructure/SessionRepositoryTest.java
index 9372e44ad..18fd14828 100644
--- a/src/test/java/nextstep/courses/infrastructure/SessionRepositoryTest.java
+++ b/src/test/java/nextstep/courses/infrastructure/SessionRepositoryTest.java
@@ -1,8 +1,8 @@
package nextstep.courses.infrastructure;
import nextstep.courses.domain.CoverImage;
+import nextstep.courses.domain.CoverImages;
import nextstep.courses.domain.Session;
-import nextstep.courses.repository.CoverImageRepository;
import nextstep.courses.repository.SessionRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -13,6 +13,7 @@
import org.springframework.jdbc.core.JdbcOperations;
import java.time.LocalDate;
+import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertAll;
@@ -26,17 +27,15 @@ class SessionRepositoryTest {
private JdbcOperations jdbcTemplates;
private SessionRepository sessionRepository;
- private CoverImageRepository coverImageRepository;
@BeforeEach
void setUp() {
sessionRepository = new JdbcSessionRepository(jdbcTemplates);
- coverImageRepository = new JdbcCoverImageRepository(jdbcTemplates);
}
@Test
void free_crud() {
- Session session = Session.ofFree(1L, 2L, coverImage(), LocalDate.now(), LocalDate.of(2023, 12, 31));
+ Session session = Session.ofFree(1L, 2L, coverImages(), LocalDate.now(), LocalDate.of(2023, 12, 31));
int count = sessionRepository.save(session);
assertThat(count).isEqualTo(1);
@@ -47,7 +46,7 @@ void free_crud() {
@Test
void paid_crud() {
- Session session = Session.ofPaid(1L, 2L, coverImage(), LocalDate.now(), LocalDate.of(2023, 12, 31), 10, 10_000L);
+ Session session = Session.ofPaid(1L, 2L, coverImages(), LocalDate.now(), LocalDate.of(2023, 12, 31), 10, 10_000L);
int count = sessionRepository.save(session);
assertThat(count).isEqualTo(1);
@@ -60,7 +59,7 @@ void paid_crud() {
LOGGER.debug("Session: {}", paidSession);
}
- private CoverImage coverImage() {
- return coverImageRepository.findById(2L);
+ private CoverImages coverImages() {
+ return new CoverImages(List.of(new CoverImage(1, "jpg", 300, 200)));
}
}
diff --git a/src/test/java/nextstep/courses/infrastructure/StudentsRepositoryTest.java b/src/test/java/nextstep/courses/infrastructure/StudentsRepositoryTest.java
index ccd17d206..db57a6084 100644
--- a/src/test/java/nextstep/courses/infrastructure/StudentsRepositoryTest.java
+++ b/src/test/java/nextstep/courses/infrastructure/StudentsRepositoryTest.java
@@ -37,15 +37,14 @@ void setUp() {
void crud() {
NsUser nsUser = new NsUser(1L, "javajigi", "test", "μλ°μ§κΈ°", "javajigi@slipp.net");
Session session = sessionRepository.findById(3L);
- session.openSession();
+ session.startRecruiting();
- session.register(Payment.ofPaid(1L, 1L, nsUser, 20_000L));
- int count = studentsRepository.save(nsUser.getId(), 2L);
- assertThat(count).isEqualTo(1);
+ session.register(Payment.ofPaid(1L, 3L, nsUser, 20_000L));
+ Long id = studentsRepository.save(nsUser.getId(), 3L);
+ assertThat(id).isEqualTo(1L);
- Students students = studentsRepository.findBySessionId(2L);
- System.out.println(students);
- assertThat(students.isContains(nsUser)).isTrue(); //μ falseμΈμ§ λͺ¨λ₯΄κ² μ γ
γ
+ Students students = studentsRepository.findBySessionId(3L);
+ assertThat(students.isContains(nsUser)).isTrue();
LOGGER.debug("Students: {}", students);
}
}