From 3db1674848cbf2ed1e3e93472b95aa9d0958d136 Mon Sep 17 00:00:00 2001 From: ingpyo Date: Sat, 2 Mar 2024 16:56:39 +0900 Subject: [PATCH 01/15] =?UTF-8?q?feat:=20=EA=B3=BD=EB=91=90=EC=B2=A0=20?= =?UTF-8?q?=EB=BC=88=EB=8C=80=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=A0=95?= =?UTF-8?q?=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/doochul/domain/BaseEntity.java | 29 +++++++++++ .../org/doochul/domain/lesson/Lesson.java | 28 +++++++++++ .../domain/lesson/LessonRepository.java | 8 ++++ .../doochul/domain/membership/MemberShip.java | 30 ++++++++++++ .../membership/MemberShipRepository.java | 8 ++++ .../java/org/doochul/domain/user/Gender.java | 5 ++ .../org/doochul/domain/user/Identity.java | 5 ++ .../java/org/doochul/domain/user/User.java | 48 +++++++++++++++++++ .../doochul/domain/user/UserRepository.java | 8 ++++ 9 files changed, 169 insertions(+) create mode 100644 doochul/src/main/java/org/doochul/domain/BaseEntity.java create mode 100644 doochul/src/main/java/org/doochul/domain/lesson/Lesson.java create mode 100644 doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java create mode 100644 doochul/src/main/java/org/doochul/domain/membership/MemberShip.java create mode 100644 doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java create mode 100644 doochul/src/main/java/org/doochul/domain/user/Gender.java create mode 100644 doochul/src/main/java/org/doochul/domain/user/Identity.java create mode 100644 doochul/src/main/java/org/doochul/domain/user/User.java create mode 100644 doochul/src/main/java/org/doochul/domain/user/UserRepository.java diff --git a/doochul/src/main/java/org/doochul/domain/BaseEntity.java b/doochul/src/main/java/org/doochul/domain/BaseEntity.java new file mode 100644 index 0000000..9b9df2b --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/BaseEntity.java @@ -0,0 +1,29 @@ +package org.doochul.domain; + +import jakarta.persistence.Column; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.PreUpdate; +import lombok.Getter; +import org.antlr.v4.runtime.misc.NotNull; + +import java.time.LocalDateTime; + +@Getter +@MappedSuperclass +public abstract class BaseEntity { + @NotNull + @Column(updatable = false) + private LocalDateTime createdAt; + @NotNull + private LocalDateTime updatedAt; + + public BaseEntity() { + this.createdAt = LocalDateTime.now(); + this.updatedAt = LocalDateTime.now(); + } + + @PreUpdate + public void update() { + this.updatedAt = LocalDateTime.now(); + } +} diff --git a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java new file mode 100644 index 0000000..0df947b --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java @@ -0,0 +1,28 @@ +package org.doochul.domain.lesson; + +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import org.doochul.domain.BaseEntity; +import org.doochul.domain.membership.MemberShip; + +import java.time.LocalDateTime; + +public class Lesson extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @ManyToOne + @JoinColumn(name = "membership_id") + private MemberShip memberShip; + + private String record; + + private LocalDateTime startedAt; + + private LocalDateTime endedAt; +} diff --git a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java new file mode 100644 index 0000000..d01d19c --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java @@ -0,0 +1,8 @@ +package org.doochul.domain.lesson; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface LessonRepository extends JpaRepository { +} diff --git a/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java b/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java new file mode 100644 index 0000000..8c8a9d4 --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java @@ -0,0 +1,30 @@ +package org.doochul.domain.membership; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.doochul.domain.BaseEntity; +import org.doochul.domain.user.User; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class MemberShip extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne + private User student; + + @OneToOne + private User trainer; + + private Integer count; +} diff --git a/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java b/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java new file mode 100644 index 0000000..ae66143 --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java @@ -0,0 +1,8 @@ +package org.doochul.domain.membership; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface MemberShipRepository extends JpaRepository { +} diff --git a/doochul/src/main/java/org/doochul/domain/user/Gender.java b/doochul/src/main/java/org/doochul/domain/user/Gender.java new file mode 100644 index 0000000..cf029cc --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/user/Gender.java @@ -0,0 +1,5 @@ +package org.doochul.domain.user; + +public enum Gender { + MEN, WOMEN +} diff --git a/doochul/src/main/java/org/doochul/domain/user/Identity.java b/doochul/src/main/java/org/doochul/domain/user/Identity.java new file mode 100644 index 0000000..da5d21e --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/user/Identity.java @@ -0,0 +1,5 @@ +package org.doochul.domain.user; + +public enum Identity { + GENERAL, TEACHER +} diff --git a/doochul/src/main/java/org/doochul/domain/user/User.java b/doochul/src/main/java/org/doochul/domain/user/User.java new file mode 100644 index 0000000..0a9bdad --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/user/User.java @@ -0,0 +1,48 @@ +package org.doochul.domain.user; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.antlr.v4.runtime.misc.NotNull; +import org.doochul.domain.BaseEntity; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class User extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NotNull + private String name; + + private String deviceToken; + + private String passWord; + + private Gender gender; + + private Identity identity; + + public User( + final Long id, + final String name, + final String deviceToken, + final String passWord, + final Gender gender, + final Identity identity + ) { + this.id = id; + this.name = name; + this.deviceToken = deviceToken; + this.passWord = passWord; + this.gender = gender; + this.identity = identity; + } +} diff --git a/doochul/src/main/java/org/doochul/domain/user/UserRepository.java b/doochul/src/main/java/org/doochul/domain/user/UserRepository.java new file mode 100644 index 0000000..6381b8b --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/user/UserRepository.java @@ -0,0 +1,8 @@ +package org.doochul.domain.user; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface UserRepository extends JpaRepository { +} From 9ebbfc1f7ba582caa62e0e3ad1bddf6d37b2508e Mon Sep 17 00:00:00 2001 From: yuseonjun Date: Sun, 3 Mar 2024 15:32:16 +0900 Subject: [PATCH 02/15] =?UTF-8?q?feat:=20=EA=B3=BD=EB=91=90=EC=B2=A0=20?= =?UTF-8?q?=EB=BC=88=EB=8C=80=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=9E=AC?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../doochul/application/ProductService.java | 20 +++++++++++ .../java/org/doochul/domain/BaseEntity.java | 8 ++--- .../org/doochul/domain/lesson/Lesson.java | 16 ++++++--- .../domain/lesson/LessonRepository.java | 2 -- .../doochul/domain/membership/MemberShip.java | 16 +++++---- .../membership/MemberShipRepository.java | 4 +-- .../org/doochul/domain/product/Product.java | 36 +++++++++++++++++++ .../domain/product/ProductRepository.java | 10 ++++++ .../doochul/domain/product/ProductType.java | 5 +++ .../java/org/doochul/domain/user/User.java | 28 ++++++--------- .../org/doochul/ui/MemberShipController.java | 9 +++++ .../org/doochul/ui/ProductController.java | 25 +++++++++++++ .../org/doochul/ui/dto/ProductResponse.java | 27 ++++++++++++++ 13 files changed, 169 insertions(+), 37 deletions(-) create mode 100644 doochul/src/main/java/org/doochul/application/ProductService.java create mode 100644 doochul/src/main/java/org/doochul/domain/product/Product.java create mode 100644 doochul/src/main/java/org/doochul/domain/product/ProductRepository.java create mode 100644 doochul/src/main/java/org/doochul/domain/product/ProductType.java create mode 100644 doochul/src/main/java/org/doochul/ui/MemberShipController.java create mode 100644 doochul/src/main/java/org/doochul/ui/ProductController.java create mode 100644 doochul/src/main/java/org/doochul/ui/dto/ProductResponse.java diff --git a/doochul/src/main/java/org/doochul/application/ProductService.java b/doochul/src/main/java/org/doochul/application/ProductService.java new file mode 100644 index 0000000..67d57da --- /dev/null +++ b/doochul/src/main/java/org/doochul/application/ProductService.java @@ -0,0 +1,20 @@ +package org.doochul.application; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.doochul.domain.product.Product; +import org.doochul.domain.product.ProductRepository; +import org.doochul.ui.dto.ProductResponse; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class ProductService { + + private final ProductRepository productRepository; + + public List findMemberShipsById(Long userId) { + List products = productRepository.findByUserId(userId); + return ProductResponse.fromList(products); + } +} diff --git a/doochul/src/main/java/org/doochul/domain/BaseEntity.java b/doochul/src/main/java/org/doochul/domain/BaseEntity.java index 9b9df2b..47e1958 100644 --- a/doochul/src/main/java/org/doochul/domain/BaseEntity.java +++ b/doochul/src/main/java/org/doochul/domain/BaseEntity.java @@ -4,17 +4,17 @@ import jakarta.persistence.MappedSuperclass; import jakarta.persistence.PreUpdate; import lombok.Getter; -import org.antlr.v4.runtime.misc.NotNull; import java.time.LocalDateTime; @Getter @MappedSuperclass public abstract class BaseEntity { - @NotNull - @Column(updatable = false) + + @Column(updatable = false, nullable = false) private LocalDateTime createdAt; - @NotNull + + @Column(nullable = false) private LocalDateTime updatedAt; public BaseEntity() { diff --git a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java index 0df947b..0110daf 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java @@ -1,15 +1,21 @@ package org.doochul.domain.lesson; +import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; -import org.doochul.domain.BaseEntity; -import org.doochul.domain.membership.MemberShip; - import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.doochul.domain.BaseEntity; +import org.doochul.domain.memberShip.MemberShip; +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class Lesson extends BaseEntity { @Id @@ -20,9 +26,9 @@ public class Lesson extends BaseEntity { @JoinColumn(name = "membership_id") private MemberShip memberShip; - private String record; - private LocalDateTime startedAt; private LocalDateTime endedAt; + + private String record; } diff --git a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java index d01d19c..eecf4d6 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java @@ -1,8 +1,6 @@ package org.doochul.domain.lesson; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; -@Repository public interface LessonRepository extends JpaRepository { } diff --git a/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java b/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java index 8c8a9d4..822fbbb 100644 --- a/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java +++ b/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java @@ -1,14 +1,16 @@ -package org.doochul.domain.membership; +package org.doochul.domain.memberShip; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; -import jakarta.persistence.OneToOne; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import org.doochul.domain.BaseEntity; +import org.doochul.domain.product.Product; import org.doochul.domain.user.User; @Entity @@ -20,11 +22,13 @@ public class MemberShip extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @OneToOne + @ManyToOne + @JoinColumn(name = "user_id") private User student; - @OneToOne - private User trainer; + @ManyToOne + @JoinColumn(name = "product_id") + private Product product; - private Integer count; + private Integer remainingCount; } diff --git a/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java b/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java index ae66143..e255ab2 100644 --- a/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java +++ b/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java @@ -1,8 +1,8 @@ -package org.doochul.domain.membership; +package org.doochul.domain.memberShip; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository -public interface MemberShipRepository extends JpaRepository { +public interface MemberShipRepository extends JpaRepository { } diff --git a/doochul/src/main/java/org/doochul/domain/product/Product.java b/doochul/src/main/java/org/doochul/domain/product/Product.java new file mode 100644 index 0000000..f9ba1b5 --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/product/Product.java @@ -0,0 +1,36 @@ +package org.doochul.domain.product; + +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.doochul.domain.BaseEntity; +import org.doochul.domain.user.User; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Product extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + @Enumerated(EnumType.STRING) + private ProductType type; + + @ManyToOne + @JoinColumn(name = "teacher_id") + private User teacher; + + private Integer count; +} diff --git a/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java b/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java new file mode 100644 index 0000000..1cb880e --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java @@ -0,0 +1,10 @@ +package org.doochul.domain.product; + +import java.util.List; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface ProductRepository extends JpaRepository { + List findByUserId(Long userId); +} diff --git a/doochul/src/main/java/org/doochul/domain/product/ProductType.java b/doochul/src/main/java/org/doochul/domain/product/ProductType.java new file mode 100644 index 0000000..458dd86 --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/product/ProductType.java @@ -0,0 +1,5 @@ +package org.doochul.domain.product; + +public enum ProductType { + LOL, TFT +} diff --git a/doochul/src/main/java/org/doochul/domain/user/User.java b/doochul/src/main/java/org/doochul/domain/user/User.java index 0a9bdad..db23e27 100644 --- a/doochul/src/main/java/org/doochul/domain/user/User.java +++ b/doochul/src/main/java/org/doochul/domain/user/User.java @@ -1,48 +1,40 @@ package org.doochul.domain.user; +import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import org.antlr.v4.runtime.misc.NotNull; +import lombok.RequiredArgsConstructor; import org.doochul.domain.BaseEntity; @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "users") +@RequiredArgsConstructor public class User extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @NotNull + @Column(nullable = false) private String name; private String deviceToken; private String passWord; + @Enumerated(EnumType.STRING) private Gender gender; + @Enumerated(EnumType.STRING) private Identity identity; - - public User( - final Long id, - final String name, - final String deviceToken, - final String passWord, - final Gender gender, - final Identity identity - ) { - this.id = id; - this.name = name; - this.deviceToken = deviceToken; - this.passWord = passWord; - this.gender = gender; - this.identity = identity; - } } diff --git a/doochul/src/main/java/org/doochul/ui/MemberShipController.java b/doochul/src/main/java/org/doochul/ui/MemberShipController.java new file mode 100644 index 0000000..69b77ad --- /dev/null +++ b/doochul/src/main/java/org/doochul/ui/MemberShipController.java @@ -0,0 +1,9 @@ +package org.doochul.ui; + +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class MemberShipController { + + +} diff --git a/doochul/src/main/java/org/doochul/ui/ProductController.java b/doochul/src/main/java/org/doochul/ui/ProductController.java new file mode 100644 index 0000000..fbf9524 --- /dev/null +++ b/doochul/src/main/java/org/doochul/ui/ProductController.java @@ -0,0 +1,25 @@ +package org.doochul.ui; + +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.doochul.application.ProductService; +import org.doochul.ui.dto.ProductResponse; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/memberShip") +public class ProductController { + + private final ProductService productService; + + @GetMapping("/{userId}") + private ResponseEntity> findMemberShipsById(@PathVariable Long userId) { + List response = productService.findMemberShipsById(userId); + return ResponseEntity.ok(response); + } +} diff --git a/doochul/src/main/java/org/doochul/ui/dto/ProductResponse.java b/doochul/src/main/java/org/doochul/ui/dto/ProductResponse.java new file mode 100644 index 0000000..1852217 --- /dev/null +++ b/doochul/src/main/java/org/doochul/ui/dto/ProductResponse.java @@ -0,0 +1,27 @@ +package org.doochul.ui.dto; + +import java.time.LocalDateTime; +import java.util.List; +import org.doochul.domain.product.Product; +import org.doochul.domain.product.ProductType; +import org.doochul.domain.user.User; + +public record ProductResponse( + Long id, + ProductType type, + User user, + int count, + LocalDateTime createdAt, + LocalDateTime updatedAt +) { + public static ProductResponse from(Product product) { + return new ProductResponse(product.getId(), product.getType(), product.getTeacher(), + product.getCount(), product.getCreatedAt(), product.getUpdatedAt()); + } + + public static List fromList(List products) { + return products.stream() + .map(ProductResponse::from) + .toList(); + } +} From de5735491804de921a9854338a45934015afa4e0 Mon Sep 17 00:00:00 2001 From: ingpyo <109223081+ingpyo@users.noreply.github.com> Date: Fri, 8 Mar 2024 13:36:11 +0900 Subject: [PATCH 03/15] =?UTF-8?q?[Feat]=20fcm=20=EB=A9=94=EC=8B=9C?= =?UTF-8?q?=EC=A7=80=20=EC=95=8C=EB=9E=8C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: 외부통신을 위한 webflux의존성 추가 * feat: KAKAO API를 통해 메시지를 보내는 기능 구현 * feat: 시스템 시간 정의(Clock) * chore: firebase의존성 주입 * feat: fcm을 사용해 알람기능 구현 * feat: 이벤트 객체 정의(수업 생성) * feat: lessonid에 따른 객체 찾는 기능구현 * feat: 이벤트 객체 정의(수업 철회) * feat: 알람 기능 추상화 밑 스케줄러 기능 구현 * feat: Letter기능 및 알람 메시지 구현 * feat: 오후 **시 **분 형식으로 변경하는 메서드 구현 * feat: 알람기능 구현(수업신청, 수업철회) * feat: 알람기능의 필요한 스케줄 기능 추가 * chore: DB의존성 추가 * feat:서버가 재시작했을때 알림을 초기화해주는 기능구현 * feat: 알람 확인을 위한 프론트코드 구현 * feat: firebase 설정 추가 * feat: 알람 테스트를 위한 컨트롤러 작성 * feat: 스케쥴러 빈 등록 * feat: Redis를 활용하여 분산된서버일 때 중복으로 알람이 발생하는 문제 해결로직 작성 --------- Co-authored-by: yuseonjun --- doochul/build.gradle | 7 ++ .../org/doochul/application/RedisService.java | 25 ++++ .../java/org/doochul/config/AppConfig.java | 31 +++++ .../java/org/doochul/config/RedisConfig.java | 26 +++++ .../org/doochul/config/SchedulingConfig.java | 10 ++ .../org/doochul/domain/lesson/Lesson.java | 2 +- .../domain/lesson/LessonRepository.java | 8 ++ .../doochul/domain/membership/MemberShip.java | 17 ++- .../membership/MemberShipRepository.java | 2 +- .../domain/membership/MemberShipType.java | 5 + .../java/org/doochul/domain/user/User.java | 1 - .../doochul/domain/user/UserRepository.java | 3 + .../org/doochul/infra/FcmMessageSender.java | 67 +++++++++++ .../doochul/service/LessonCreateEvent.java | 11 ++ .../org/doochul/service/LessonStatus.java | 40 +++++++ .../doochul/service/LessonWithdrawnEvent.java | 11 ++ .../main/java/org/doochul/service/Letter.java | 21 ++++ .../doochul/service/MessageSendManager.java | 5 + .../service/NotificationEventListener.java | 26 +++++ .../doochul/service/NotificationService.java | 107 ++++++++++++++++++ .../org/doochul/support/KeyGenerator.java | 6 + .../org/doochul/support/KeyGeneratorImpl.java | 12 ++ .../java/org/doochul/ui/FCMController.java | 19 ++++ .../src/main/resources/application.properties | 3 + ...43-firebase-adminsdk-oyokf-f075393454.json | 13 +++ .../resources/static/firebase-messaging-sw.js | 20 ++++ .../src/main/resources/templates/index.html | 57 ++++++++++ .../org/doochul/service/LessonStatusTest.java | 69 +++++++++++ .../service/NotificationServiceTest.java | 52 +++++++++ 29 files changed, 672 insertions(+), 4 deletions(-) create mode 100644 doochul/src/main/java/org/doochul/application/RedisService.java create mode 100644 doochul/src/main/java/org/doochul/config/AppConfig.java create mode 100644 doochul/src/main/java/org/doochul/config/RedisConfig.java create mode 100644 doochul/src/main/java/org/doochul/config/SchedulingConfig.java create mode 100644 doochul/src/main/java/org/doochul/domain/membership/MemberShipType.java create mode 100644 doochul/src/main/java/org/doochul/infra/FcmMessageSender.java create mode 100644 doochul/src/main/java/org/doochul/service/LessonCreateEvent.java create mode 100644 doochul/src/main/java/org/doochul/service/LessonStatus.java create mode 100644 doochul/src/main/java/org/doochul/service/LessonWithdrawnEvent.java create mode 100644 doochul/src/main/java/org/doochul/service/Letter.java create mode 100644 doochul/src/main/java/org/doochul/service/MessageSendManager.java create mode 100644 doochul/src/main/java/org/doochul/service/NotificationEventListener.java create mode 100644 doochul/src/main/java/org/doochul/service/NotificationService.java create mode 100644 doochul/src/main/java/org/doochul/support/KeyGenerator.java create mode 100644 doochul/src/main/java/org/doochul/support/KeyGeneratorImpl.java create mode 100644 doochul/src/main/java/org/doochul/ui/FCMController.java create mode 100644 doochul/src/main/resources/kwakdoochul-bbb43-firebase-adminsdk-oyokf-f075393454.json create mode 100644 doochul/src/main/resources/static/firebase-messaging-sw.js create mode 100644 doochul/src/main/resources/templates/index.html create mode 100644 doochul/src/test/java/org/doochul/service/LessonStatusTest.java create mode 100644 doochul/src/test/java/org/doochul/service/NotificationServiceTest.java diff --git a/doochul/build.gradle b/doochul/build.gradle index f5fa55c..81f9f50 100644 --- a/doochul/build.gradle +++ b/doochul/build.gradle @@ -24,6 +24,13 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-webflux' + implementation 'org.springframework.boot:spring-boot-starter-data-redis' + + implementation 'com.google.firebase:firebase-admin:9.2.0' + + runtimeOnly 'mysql:mysql-connector-java' + runtimeOnly 'com.h2database:h2' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/doochul/src/main/java/org/doochul/application/RedisService.java b/doochul/src/main/java/org/doochul/application/RedisService.java new file mode 100644 index 0000000..5bd1be3 --- /dev/null +++ b/doochul/src/main/java/org/doochul/application/RedisService.java @@ -0,0 +1,25 @@ +package org.doochul.application; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.time.Duration; + +@Service +public class RedisService { + + private final RedisTemplate redisTemplate; + + public RedisService(final RedisTemplate redisTemplate) { + this.redisTemplate = redisTemplate; + } + + public void delete(final String key) { + redisTemplate.delete(key); + } + + + public boolean setNX(final String key, final String value, final Duration duration) { + return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, duration)); + } +} diff --git a/doochul/src/main/java/org/doochul/config/AppConfig.java b/doochul/src/main/java/org/doochul/config/AppConfig.java new file mode 100644 index 0000000..7476aaa --- /dev/null +++ b/doochul/src/main/java/org/doochul/config/AppConfig.java @@ -0,0 +1,31 @@ +package org.doochul.config; + +import java.time.Clock; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +@Configuration +public class AppConfig { + + @Bean + public Clock clock() { + return Clock.systemDefaultZone(); + } + + @Bean + public TaskScheduler taskScheduler() { + ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); + taskScheduler.setPoolSize(10); + return taskScheduler; + } + + @Bean + public ThreadPoolTaskScheduler taskScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setPoolSize(2); + return scheduler; + } +} diff --git a/doochul/src/main/java/org/doochul/config/RedisConfig.java b/doochul/src/main/java/org/doochul/config/RedisConfig.java new file mode 100644 index 0000000..8e27f1d --- /dev/null +++ b/doochul/src/main/java/org/doochul/config/RedisConfig.java @@ -0,0 +1,26 @@ +package org.doochul.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +public class RedisConfig { + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(); + } + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new StringRedisSerializer()); + return redisTemplate; + } +} diff --git a/doochul/src/main/java/org/doochul/config/SchedulingConfig.java b/doochul/src/main/java/org/doochul/config/SchedulingConfig.java new file mode 100644 index 0000000..0e6ee09 --- /dev/null +++ b/doochul/src/main/java/org/doochul/config/SchedulingConfig.java @@ -0,0 +1,10 @@ +package org.doochul.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class SchedulingConfig { + +} \ No newline at end of file diff --git a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java index 0110daf..aca87ee 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java @@ -11,7 +11,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import org.doochul.domain.BaseEntity; -import org.doochul.domain.memberShip.MemberShip; +import org.doochul.domain.membership.MemberShip; @Entity @Getter diff --git a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java index eecf4d6..fb3fe1b 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java @@ -2,5 +2,13 @@ import org.springframework.data.jpa.repository.JpaRepository; +import java.time.LocalDateTime; +import java.util.List; + public interface LessonRepository extends JpaRepository { + default Lesson getById(final Long id) { + return findById(id).orElseThrow(() -> new IllegalArgumentException("해당 수업이 없습니다.")); + } + + List findByStartedAtBefore(final LocalDateTime currentServerTime); } diff --git a/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java b/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java index 822fbbb..382e41b 100644 --- a/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java +++ b/doochul/src/main/java/org/doochul/domain/membership/MemberShip.java @@ -1,4 +1,4 @@ -package org.doochul.domain.memberShip; +package org.doochul.domain.membership; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -31,4 +31,19 @@ public class MemberShip extends BaseEntity { private Product product; private Integer remainingCount; + + public void decreasedCount() { + validateMinRemainingCount(); + remainingCount -= 1; + } + + public boolean isCountZero() { + return remainingCount == 0; + } + + private void validateMinRemainingCount() { + if (remainingCount < 1) { + throw new IllegalArgumentException("안돼"); + } + } } diff --git a/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java b/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java index e255ab2..860ce34 100644 --- a/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java +++ b/doochul/src/main/java/org/doochul/domain/membership/MemberShipRepository.java @@ -1,4 +1,4 @@ -package org.doochul.domain.memberShip; +package org.doochul.domain.membership; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; diff --git a/doochul/src/main/java/org/doochul/domain/membership/MemberShipType.java b/doochul/src/main/java/org/doochul/domain/membership/MemberShipType.java new file mode 100644 index 0000000..2d06ee2 --- /dev/null +++ b/doochul/src/main/java/org/doochul/domain/membership/MemberShipType.java @@ -0,0 +1,5 @@ +package org.doochul.domain.membership; + +public enum MemberShipType { + LOL, TFT +} \ No newline at end of file diff --git a/doochul/src/main/java/org/doochul/domain/user/User.java b/doochul/src/main/java/org/doochul/domain/user/User.java index db23e27..39391b8 100644 --- a/doochul/src/main/java/org/doochul/domain/user/User.java +++ b/doochul/src/main/java/org/doochul/domain/user/User.java @@ -18,7 +18,6 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Table(name = "users") -@RequiredArgsConstructor public class User extends BaseEntity { @Id diff --git a/doochul/src/main/java/org/doochul/domain/user/UserRepository.java b/doochul/src/main/java/org/doochul/domain/user/UserRepository.java index 6381b8b..08b5d50 100644 --- a/doochul/src/main/java/org/doochul/domain/user/UserRepository.java +++ b/doochul/src/main/java/org/doochul/domain/user/UserRepository.java @@ -5,4 +5,7 @@ @Repository public interface UserRepository extends JpaRepository { + default User getById(final Long id) { + return findById(id).orElseThrow(() -> new IllegalArgumentException("해당 유저는 없습니다.")); + } } diff --git a/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java b/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java new file mode 100644 index 0000000..d600580 --- /dev/null +++ b/doochul/src/main/java/org/doochul/infra/FcmMessageSender.java @@ -0,0 +1,67 @@ +package org.doochul.infra; + +import com.google.auth.oauth2.GoogleCredentials; +import com.google.firebase.FirebaseApp; +import com.google.firebase.FirebaseOptions; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.Message; +import com.google.firebase.messaging.Notification; +import jakarta.annotation.PostConstruct; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.doochul.service.Letter; +import org.doochul.service.MessageSendManager; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.ClassPathResource; +import org.springframework.stereotype.Component; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +@Slf4j +@Component +@RequiredArgsConstructor +public class FcmMessageSender implements MessageSendManager { + + @Value("${fcm.certification.path}") + private String FCM_CERTIFICATION_PATH; + + @PostConstruct + public void initialize() { + try { + ClassPathResource resource = new ClassPathResource(FCM_CERTIFICATION_PATH); + FirebaseOptions options = FirebaseOptions.builder() + .setCredentials(GoogleCredentials.fromStream(resource.getInputStream())) + .build(); + + if (FirebaseApp.getApps().isEmpty()) { + FirebaseApp.initializeApp(options); + } + } catch (FileNotFoundException e) { + log.error("파일을 찾을 수 없습니다. ", e); + } catch (IOException e) { + log.error("FCM 인증이 실패했습니다. ", e); + } + } + + @Override + public void sendTo(final Letter letter) { + final Notification notification = Notification.builder() + .setTitle(letter.title()) + .setBody(letter.body()) + .build(); + final Message message = Message.builder() + .setToken(letter.targetToken()) + .setNotification(notification) + .build(); + try { + final String response = FirebaseMessaging.getInstance().sendAsync(message).get(); + log.info("알림 전송 성공 : " + response); + } catch (InterruptedException e) { + log.error("FCM 알림 스레드에서 문제가 발생했습니다.", e); + } catch (ExecutionException e) { + log.error("FCM 알림 전송에 실패했습니다.", e); + } + } +} \ No newline at end of file diff --git a/doochul/src/main/java/org/doochul/service/LessonCreateEvent.java b/doochul/src/main/java/org/doochul/service/LessonCreateEvent.java new file mode 100644 index 0000000..9b5fbb2 --- /dev/null +++ b/doochul/src/main/java/org/doochul/service/LessonCreateEvent.java @@ -0,0 +1,11 @@ +package org.doochul.service; + +import org.doochul.domain.lesson.Lesson; +import org.doochul.domain.user.User; + +public record LessonCreateEvent( + User student, + User teacher, + Lesson lesson +) { +} diff --git a/doochul/src/main/java/org/doochul/service/LessonStatus.java b/doochul/src/main/java/org/doochul/service/LessonStatus.java new file mode 100644 index 0000000..e47b77f --- /dev/null +++ b/doochul/src/main/java/org/doochul/service/LessonStatus.java @@ -0,0 +1,40 @@ +package org.doochul.service; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +@FunctionalInterface +interface LessonStatusMessage { + String getMessage(String name, LocalDateTime time, String teacher); +} + +public enum LessonStatus { + BEFORE_LESSON("수업 전", + (name, time, teacher) -> name + "님 " + formatToLocalTime(time) + " " + teacher + " 강사님 수업 잊지 않으셨죠?"), + AFTER_LESSON("수업 후", (name, time, teacher) -> name + "님 오늘 수업 잘 받으셨나요?"), + SCHEDULED_LESSON("수업 신청", + (name, time, teacher) -> formatToLocalTime(time) + " " + name + "님 " + teacher + " 강사님 수업을 신청했습니다."), + WITHDRAWN_LESSON("수업 철회", + (name, time, teacher) -> formatToLocalTime(time) + " " + name + "님 " + teacher + " 강사님의 수업을 철회했습니다."), + END_LESSON("수업 종료", (name, time, teacher) -> teacher + " 강사님의 수업이 모두 종료되었습니다."); + + private final String title; + private final LessonStatusMessage message; + + LessonStatus(String title, LessonStatusMessage message) { + this.title = title; + this.message = message; + } + + private static String formatToLocalTime(LocalDateTime time) { + return time.format(DateTimeFormatter.ofPattern("a HH시 mm분")); + } + + public String getTitle() { + return title; + } + + public String getMessage(String name, LocalDateTime time, String teacher) { + return message.getMessage(name, time, teacher); + } +} diff --git a/doochul/src/main/java/org/doochul/service/LessonWithdrawnEvent.java b/doochul/src/main/java/org/doochul/service/LessonWithdrawnEvent.java new file mode 100644 index 0000000..d240bdf --- /dev/null +++ b/doochul/src/main/java/org/doochul/service/LessonWithdrawnEvent.java @@ -0,0 +1,11 @@ +package org.doochul.service; + +import org.doochul.domain.lesson.Lesson; +import org.doochul.domain.user.User; + +public record LessonWithdrawnEvent( + User student, + User teacher, + Lesson lesson +) { +} diff --git a/doochul/src/main/java/org/doochul/service/Letter.java b/doochul/src/main/java/org/doochul/service/Letter.java new file mode 100644 index 0000000..f18da78 --- /dev/null +++ b/doochul/src/main/java/org/doochul/service/Letter.java @@ -0,0 +1,21 @@ +package org.doochul.service; + +import org.doochul.domain.user.User; + +import java.time.LocalDateTime; + +public record Letter( + String targetToken, + String title, + String body +) { + public static Letter of( + final User student, + final User teacher, + final LocalDateTime startedAt, + final LessonStatus lessonStatus + ) { + final String message = lessonStatus.getMessage(student.getName(), startedAt, teacher.getName()); + return new Letter(student.getDeviceToken(), lessonStatus.getTitle(), message); + } +} diff --git a/doochul/src/main/java/org/doochul/service/MessageSendManager.java b/doochul/src/main/java/org/doochul/service/MessageSendManager.java new file mode 100644 index 0000000..9845d1b --- /dev/null +++ b/doochul/src/main/java/org/doochul/service/MessageSendManager.java @@ -0,0 +1,5 @@ +package org.doochul.service; + +public interface MessageSendManager { + void sendTo(final Letter letter); +} diff --git a/doochul/src/main/java/org/doochul/service/NotificationEventListener.java b/doochul/src/main/java/org/doochul/service/NotificationEventListener.java new file mode 100644 index 0000000..d76f5d1 --- /dev/null +++ b/doochul/src/main/java/org/doochul/service/NotificationEventListener.java @@ -0,0 +1,26 @@ +package org.doochul.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class NotificationEventListener { + private final NotificationService notificationService; + + @EventListener + @Async + public void scheduleLessonNotificationEvent(final LessonCreateEvent event) { + notificationService.applyForLesson(event); + } + + @EventListener + @Async + public void withdrawnLessonNotificationEvent1(final LessonWithdrawnEvent event) { + notificationService.withdrawnForLessons(event); + } +} diff --git a/doochul/src/main/java/org/doochul/service/NotificationService.java b/doochul/src/main/java/org/doochul/service/NotificationService.java new file mode 100644 index 0000000..d49bda4 --- /dev/null +++ b/doochul/src/main/java/org/doochul/service/NotificationService.java @@ -0,0 +1,107 @@ +package org.doochul.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.doochul.application.RedisService; +import org.doochul.domain.lesson.Lesson; +import org.doochul.domain.lesson.LessonRepository; +import org.doochul.domain.membership.MemberShip; +import org.doochul.domain.user.User; +import org.doochul.support.KeyGenerator; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; + +import java.time.Clock; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledFuture; + +import static org.doochul.service.LessonStatus.AFTER_LESSON; +import static org.doochul.service.LessonStatus.BEFORE_LESSON; +import static org.doochul.service.LessonStatus.END_LESSON; +import static org.doochul.service.LessonStatus.SCHEDULED_LESSON; +import static org.doochul.service.LessonStatus.WITHDRAWN_LESSON; + +@Slf4j +@Service +@RequiredArgsConstructor +public class NotificationService { + private final TaskScheduler taskScheduler; + private final MessageSendManager messageSendManager; + private final Clock clock; + private final LessonRepository lessonRepository; + private final KeyGenerator keyGenerator; + private final RedisService redisService; + + private final Map>> schedule = new HashMap<>(); + + @EventListener(ApplicationReadyEvent.class) + public void initLessonNotification() { + final List lessons = lessonRepository.findByStartedAtBefore(LocalDateTime.now()); + lessons.forEach(lesson -> { + addRemindNotificationSchedule(lesson.getMemberShip().getStudent(), lesson.getMemberShip().getProduct().getTeacher(), lesson); + addDismissalNotificationSchedule(lesson.getMemberShip().getStudent(), lesson.getMemberShip().getProduct().getTeacher(), lesson); + }); + } + + public void applyForLesson(final LessonCreateEvent event) { + final User student = event.student(); + final User teacher = event.teacher(); + final Lesson lesson = event.lesson(); + sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), SCHEDULED_LESSON)); + addRemindNotificationSchedule(student,teacher,lesson); + addDismissalNotificationSchedule(student,teacher,lesson); + } + + public void withdrawnForLessons(final LessonWithdrawnEvent event) { + sendNotification(Letter.of(event.student(), event.teacher(), event.lesson().getStartedAt(), WITHDRAWN_LESSON)); + schedule.get(event.lesson().getId()) + .forEach(ScheduledFuture -> ScheduledFuture.cancel(true)); + schedule.remove(event.lesson().getId()); + } + + @Async + public void sendNotification(final Letter letter) { + final String key = keyGenerator.generateAccountKey(letter.targetToken()); + if (redisService.setNX(key, "notification", Duration.ofSeconds(5))) { + messageSendManager.sendTo(letter); + redisService.delete(key); + } + } + + private void addRemindNotificationSchedule(final User student, final User teacher, final Lesson lesson) { + final LocalDateTime reminderTime = lesson.getStartedAt().minusMinutes(10); + final Instant instant = toInstant(reminderTime); + final ScheduledFuture remindSchedule = taskScheduler.schedule(() -> sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), BEFORE_LESSON)), instant); + final List> lessonSchedules = schedule.computeIfAbsent(lesson.getId(), k -> new ArrayList<>()); + lessonSchedules.add(remindSchedule); + } + + private void addDismissalNotificationSchedule(final User student, final User teacher, final Lesson lesson) { + final Instant instant = toInstant(lesson.getEndedAt()); + final ScheduledFuture dismissalSchedule = taskScheduler.schedule(() -> deductCountAndSendNotification(student, teacher, lesson), instant); + final List> lessonSchedules = schedule.computeIfAbsent(lesson.getId(), k -> new ArrayList<>()); + lessonSchedules.add(dismissalSchedule); + } + + private void deductCountAndSendNotification(final User student, final User teacher, final Lesson lesson) { + final MemberShip memberShip = lesson.getMemberShip(); + memberShip.decreasedCount(); + sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), AFTER_LESSON)); + if (memberShip.isCountZero()) { + sendNotification(Letter.of(student, teacher, lesson.getStartedAt(), END_LESSON)); + } + } + + private Instant toInstant(final LocalDateTime localDateTime) { + return localDateTime.atZone(clock.getZone()).toInstant(); + } +} diff --git a/doochul/src/main/java/org/doochul/support/KeyGenerator.java b/doochul/src/main/java/org/doochul/support/KeyGenerator.java new file mode 100644 index 0000000..ffa00d6 --- /dev/null +++ b/doochul/src/main/java/org/doochul/support/KeyGenerator.java @@ -0,0 +1,6 @@ +package org.doochul.support; + +public interface KeyGenerator { + + String generateAccountKey(String token); +} diff --git a/doochul/src/main/java/org/doochul/support/KeyGeneratorImpl.java b/doochul/src/main/java/org/doochul/support/KeyGeneratorImpl.java new file mode 100644 index 0000000..3b87aad --- /dev/null +++ b/doochul/src/main/java/org/doochul/support/KeyGeneratorImpl.java @@ -0,0 +1,12 @@ +package org.doochul.support; + +import org.springframework.stereotype.Component; + +@Component +public class KeyGeneratorImpl implements KeyGenerator { + + @Override + public String generateAccountKey(String userToken) { + return userToken + ":token"; + } +} diff --git a/doochul/src/main/java/org/doochul/ui/FCMController.java b/doochul/src/main/java/org/doochul/ui/FCMController.java new file mode 100644 index 0000000..5372f0a --- /dev/null +++ b/doochul/src/main/java/org/doochul/ui/FCMController.java @@ -0,0 +1,19 @@ +package org.doochul.ui; + +import lombok.RequiredArgsConstructor; +import org.doochul.infra.FcmMessageSender; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +@RequiredArgsConstructor +public class FCMController { + + private final FcmMessageSender init; + + @GetMapping("/v1") + public String v1(){ + init.initialize(); + return "index"; + } +} diff --git a/doochul/src/main/resources/application.properties b/doochul/src/main/resources/application.properties index 8b13789..7365132 100644 --- a/doochul/src/main/resources/application.properties +++ b/doochul/src/main/resources/application.properties @@ -1 +1,4 @@ +spring.datasource.url=jdbc:h2:mem:testdb;MODE=MySQL; + +fcm.certification.path=kwakdoochul-bbb43-firebase-adminsdk-oyokf-f075393454.json \ No newline at end of file diff --git a/doochul/src/main/resources/kwakdoochul-bbb43-firebase-adminsdk-oyokf-f075393454.json b/doochul/src/main/resources/kwakdoochul-bbb43-firebase-adminsdk-oyokf-f075393454.json new file mode 100644 index 0000000..39a5f4b --- /dev/null +++ b/doochul/src/main/resources/kwakdoochul-bbb43-firebase-adminsdk-oyokf-f075393454.json @@ -0,0 +1,13 @@ +{ + "type": "service_account", + "project_id": "kwakdoochul-bbb43", + "private_key_id": "f075393454aacff2614abfc5fa982bc9028da599", + "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDSF2TQnKW0ZiGE\nc4NJEXWgZ4y5BJe8f+ifZute82X6HnNcyL80vRf2B9EOOOwsJeu/BFwBHOer+tOa\nWzGhvSgFyo9u0zkQMXiIbQGXwqb+sEYZQkUFSxncd753s8GaVLsyybYTvJxlmg8R\nuF4Ut1LPuvvnkEC9Zkn7sp2ueKkumBAfCex/+bsEA25UdqQfy7Bv14UyTvzvKMBU\nYO7lWKsC4T8hqRoXcysGF5RjnptXp+Qrnwar6r3uTbSLGj5tuiI9ooT2oZYqcux1\nNvTwPqVVjADH6iVJ/w3mteFtlQ35bODdo7ifL8Rcl/y9Eo1zkN18mo5ivCZxpx65\nBM8w81hXAgMBAAECggEAO9gGE5ZLbTOaYIw23V1n0CUu5JT2U+9rZ9x9NzLF3ZVG\n7ysPrAohBSf82LxGKd0zZdnsCzUcmNR96f4ICTZEbEHi0YLBQmeVGedTCNOdlfbI\nQPGrj3JxD2fcjWRaxYdVO4ZRoxWaxyY3HKkTw3rkz99HWhKxHkJA2L1sRQKBzo9l\n9NVprgDw3emWyWih5jpgtWwM2umpcB3JrEcmqMW30jhJYOz94+P1JRAX/coPfeHa\njZUnTDnuP4/XW/efnVwN3DPc+TADVsFZ0J5X3foQbm3qcUYHxlH4qZg1DwEPA5wS\nKiGE8A8PDsGm7vEbmyNce0FYcjnpaqix05X+3B4JQQKBgQDwGmlDNM9/dNWv/pts\ntJTrZxObVgBF/zHMxDO9aqUBTEAP1wQVOd3g8QXJePiqySjib0LKOu0WaQq4XToa\nIM6jnFXM+bkqU3r6HQx4eCaCAhxhER4US55jgEUW8goFTIsE05kHI+q/6ZLRdm45\nMLNKJlXBKA9lMTEG9uiQJW7OiQKBgQDgAE2GMg+k8rQf0sPbxlJEBa7fngO5teK9\nq0NCQ/P/ZR3DDK7MkvUakL8dR8LGYBJkNH4tnLEnsSuh5LceCKHWZEd91D+FXQU2\nnBJ0LpCB/u4Mcbr+Ho1wlz9/Efn5ar3oBZpd3RKsmrlkwQTV/FakTjwxndEurRi5\n2H4uOx433wKBgEPI0QreL+5lx6YmFS79VEWZFhn2j6EzSJXslkbVgrv5EOTn6Qkt\nCwzkPqQAeQOOQvKaQprhQ+ndwd8Gws55kJz0F+0EW1gttTxDUy/3i7eMbQKiWIGW\nT6L7pYWy001nrJ+yNTOk2jNP99kWvEt9CkDWzcL4UlBZMOQsdL+tMbkxAoGAUmuK\nGuB8pSKwaC0y58DXMDQvHhSUJlbocQV9H/rE4qogA069WoSQLxAnYeyvnDJpUfmG\nm93VyVcFSPJQ9noSokIPlBrurHGHo4pVt+4SOeLFUErglPRE8rKUKHtC0SUXbzHw\nlKztXBkqMgpbbykD8DzhJRh+iYAjYu5nrzcNbV0CgYARTeYvHHEHNh50AruWpDPI\nb4uQX47m8H0KU5m3kd3uo4x4gTXGiPsgHsBkJXPVdyP53Fs1iA1woYh6v8aveWY+\nim37dwiuqM+V5rAum8Gz/i/bWeMJ+rCGcH03xqleT8YR+xx+izvE1m9kDbkpP9GL\n89SzmBbtOGd3/YkGgIwocA==\n-----END PRIVATE KEY-----\n", + "client_email": "firebase-adminsdk-oyokf@kwakdoochul-bbb43.iam.gserviceaccount.com", + "client_id": "104118801227229993047", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-oyokf%40kwakdoochul-bbb43.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" +} diff --git a/doochul/src/main/resources/static/firebase-messaging-sw.js b/doochul/src/main/resources/static/firebase-messaging-sw.js new file mode 100644 index 0000000..b81203b --- /dev/null +++ b/doochul/src/main/resources/static/firebase-messaging-sw.js @@ -0,0 +1,20 @@ +importScripts('https://www.gstatic.com/firebasejs/5.9.2/firebase-app.js'); +importScripts('https://www.gstatic.com/firebasejs/5.9.2/firebase-messaging.js'); + +// Initialize Firebase +const firebaseConfig = { + apiKey: "AIzaSyAzHogvZK_6BoCm6Qa17wBTEwvfuFEocLA", + authDomain: "kwakdoochul-bbb43.firebaseapp.com", + projectId: "kwakdoochul-bbb43", + storageBucket: "kwakdoochul-bbb43.appspot.com", + messagingSenderId: "801744474814", + appId: "1:801744474814:web:7ed72e926feb81dda684ef", + measurementId: "G-02EJZQPZ4D" +}; + +firebase.initializeApp(firebaseConfig); +const messaging = firebase.messaging(); + + + + diff --git a/doochul/src/main/resources/templates/index.html b/doochul/src/main/resources/templates/index.html new file mode 100644 index 0000000..ab3898e --- /dev/null +++ b/doochul/src/main/resources/templates/index.html @@ -0,0 +1,57 @@ + + + + + wewe + + +

Test page! dd

+ + + + + + + + + + diff --git a/doochul/src/test/java/org/doochul/service/LessonStatusTest.java b/doochul/src/test/java/org/doochul/service/LessonStatusTest.java new file mode 100644 index 0000000..f8f0b9d --- /dev/null +++ b/doochul/src/test/java/org/doochul/service/LessonStatusTest.java @@ -0,0 +1,69 @@ +package org.doochul.service; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import org.junit.jupiter.api.Test; + +class LessonStatusTest { + + @Test + void testBeforeLessonMessage() { + LocalDateTime time = LocalDateTime.now(); + LessonStatus lessonStatus = LessonStatus.BEFORE_LESSON; + String expectedMessage = "John님 " + formatToLocalTime(time) + " Math 강사님 수업 잊지 않으셨죠?"; + String actualMessage = lessonStatus.getMessage("John", time, "Math"); + + assertEquals("수업 전", lessonStatus.getTitle()); + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testAfterLessonMessage() { + LocalDateTime time = LocalDateTime.now(); + LessonStatus lessonStatus = LessonStatus.AFTER_LESSON; + String expectedMessage = "Jane님 오늘 수업 잘 받으셨나요?"; + String actualMessage = lessonStatus.getMessage("Jane", time, "English"); + + assertEquals("수업 후", lessonStatus.getTitle()); + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testScheduledLessonMessage() { + LocalDateTime time = LocalDateTime.now(); + LessonStatus lessonStatus = LessonStatus.SCHEDULED_LESSON; + String expectedMessage = formatToLocalTime(time) + " Mike님 Chemistry 강사님 수업을 신청했습니다."; + String actualMessage = lessonStatus.getMessage("Mike", time, "Chemistry"); + + assertEquals("수업 신청", lessonStatus.getTitle()); + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testWithdrawnLessonMessage() { + LocalDateTime time = LocalDateTime.now(); + LessonStatus lessonStatus = LessonStatus.WITHDRAWN_LESSON; + String expectedMessage = formatToLocalTime(time) + " Alice님 Physics 강사님의 수업을 철회했습니다."; + String actualMessage = lessonStatus.getMessage("Alice", time, "Physics"); + + assertEquals("수업 철회", lessonStatus.getTitle()); + assertEquals(expectedMessage, actualMessage); + } + + @Test + void testEndLessonMessage() { + LocalDateTime time = LocalDateTime.now(); + LessonStatus lessonStatus = LessonStatus.END_LESSON; + String expectedMessage = "History 강사님의 수업이 모두 종료되었습니다."; + String actualMessage = lessonStatus.getMessage("Bobby", time, "History"); + + assertEquals("수업 종료", lessonStatus.getTitle()); + assertEquals(expectedMessage, actualMessage); + } + + private String formatToLocalTime(LocalDateTime time) { + return time.format(DateTimeFormatter.ofPattern("a HH시 mm분")); + } +} diff --git a/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java b/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java new file mode 100644 index 0000000..4af016f --- /dev/null +++ b/doochul/src/test/java/org/doochul/service/NotificationServiceTest.java @@ -0,0 +1,52 @@ +package org.doochul.service; + +import org.doochul.application.RedisService; +import org.doochul.support.KeyGenerator; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; + +import java.time.Duration; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import static org.mockito.BDDMockito.*; + +@SpringBootTest +class NotificationServiceTest { + @MockBean + private MessageSendManager messageSendManager; + @Autowired + private KeyGenerator keyGenerator; + @Autowired + private RedisService redisService; + + @Test + void sendNotification() throws InterruptedException { + ExecutorService executorService = Executors.newFixedThreadPool(5); + CountDownLatch latch = new CountDownLatch(5); + final Letter letter = new Letter("token", "안녕?", "테스트"); + + willDoNothing().given(messageSendManager).sendTo(any(Letter.class)); + for (int i = 0; i < 5; i++) { + executorService.submit(() -> { + try { + final String key = keyGenerator.generateAccountKey(letter.targetToken()); + if (redisService.setNX(key, "notification", Duration.ofSeconds(5))) { + messageSendManager.sendTo(letter); + redisService.delete(letter.targetToken()); + } + latch.countDown(); + } catch (Exception e) { + } + }); + } + + latch.await(); + executorService.shutdown(); + + then(messageSendManager).should(times(1)).sendTo(any(Letter.class)); + } +} From 6524bbc098af0745fd1b7b62830ac4b0fb2d6540 Mon Sep 17 00:00:00 2001 From: yuseonjun Date: Sat, 9 Mar 2024 17:59:14 +0900 Subject: [PATCH 04/15] =?UTF-8?q?refactor:=20=EC=A4=91=EB=B3=B5=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doochul/src/main/java/org/doochul/config/AppConfig.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/doochul/src/main/java/org/doochul/config/AppConfig.java b/doochul/src/main/java/org/doochul/config/AppConfig.java index 7476aaa..82cab1e 100644 --- a/doochul/src/main/java/org/doochul/config/AppConfig.java +++ b/doochul/src/main/java/org/doochul/config/AppConfig.java @@ -3,8 +3,6 @@ import java.time.Clock; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.TaskScheduler; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; @Configuration @@ -15,13 +13,6 @@ public Clock clock() { return Clock.systemDefaultZone(); } - @Bean - public TaskScheduler taskScheduler() { - ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); - taskScheduler.setPoolSize(10); - return taskScheduler; - } - @Bean public ThreadPoolTaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); From 99650a3729535dd1c99d18e8a551ea7bf6f322dd Mon Sep 17 00:00:00 2001 From: yuseonjun Date: Sat, 9 Mar 2024 17:59:40 +0900 Subject: [PATCH 05/15] =?UTF-8?q?refactor:=20=EC=9E=98=EB=AA=BB=EB=90=9C?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/doochul/domain/product/ProductRepository.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java b/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java index 1cb880e..d5a3e8e 100644 --- a/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java +++ b/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java @@ -5,6 +5,6 @@ import org.springframework.stereotype.Repository; @Repository -public interface ProductRepository extends JpaRepository { - List findByUserId(Long userId); +public interface ProductRepository extends JpaRepository { + List findAll(); } From 1e51675bf43abeead0d77721364b283da3e52cac Mon Sep 17 00:00:00 2001 From: yukudaa Date: Mon, 18 Mar 2024 17:50:35 +0900 Subject: [PATCH 06/15] feat/16-create-lesson --- .../doochul/application/LessonService.java | 30 +++++++++++++++++ .../org/doochul/domain/lesson/Lesson.java | 26 +++++++++++++++ .../domain/lesson/LessonRepository.java | 4 ++- .../java/org/doochul/ui/LessonController.java | 26 +++++++++++++++ .../org/doochul/ui/dto/LessonResponse.java | 33 +++++++++++++++++++ 5 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 doochul/src/main/java/org/doochul/application/LessonService.java create mode 100644 doochul/src/main/java/org/doochul/ui/LessonController.java create mode 100644 doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java diff --git a/doochul/src/main/java/org/doochul/application/LessonService.java b/doochul/src/main/java/org/doochul/application/LessonService.java new file mode 100644 index 0000000..547e060 --- /dev/null +++ b/doochul/src/main/java/org/doochul/application/LessonService.java @@ -0,0 +1,30 @@ +package org.doochul.application; + +import lombok.RequiredArgsConstructor; +import org.doochul.domain.lesson.Lesson; +import org.doochul.domain.lesson.LessonRepository; +import org.doochul.domain.user.User; +import org.doochul.domain.user.UserRepository; +import org.doochul.ui.dto.LessonResponse; +import org.springframework.stereotype.Service; +import java.util.List; + +@Service +@RequiredArgsConstructor +public class LessonService { + + private final LessonRepository lessonRepository; + private final UserRepository userRepository; + + public List findMemberShipsById(Long userId) { + List lessons = lessonRepository.findByUserId(userId); + return LessonResponse.fromList(lessons); + } + + public Long save(final Long userId, final LessonResponse lessonResponse) { + final User user = userRepository.findById(userId).orElseThrow(); + return lessonRepository.save(Lesson.of(user,lessonResponse)).getId(); + } + + +} diff --git a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java index aca87ee..437e6ce 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java @@ -6,12 +6,16 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; + import java.time.LocalDateTime; + import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import org.doochul.domain.BaseEntity; import org.doochul.domain.membership.MemberShip; +import org.doochul.domain.user.User; +import org.doochul.ui.dto.LessonResponse; @Entity @Getter @@ -26,9 +30,31 @@ public class Lesson extends BaseEntity { @JoinColumn(name = "membership_id") private MemberShip memberShip; + @ManyToOne + @JoinColumn(name = "student_id") + private User student; + + @ManyToOne + @JoinColumn(name = "teacher_id") + private User teacher; + private LocalDateTime startedAt; private LocalDateTime endedAt; private String record; + + private Lesson(Long id, MemberShip memberShip, User student, User teacher, LocalDateTime startedAt, LocalDateTime endedAt, String record) { + this.id = id; + this.memberShip = memberShip; + this.student = student; + this.teacher = teacher; + this.startedAt = startedAt; + this.endedAt = endedAt; + this.record = record; + } + + public static Lesson of(User user,LessonResponse lessonResponse) { + return new Lesson(lessonResponse.id(), lessonResponse.memberShip(), user, user,lessonResponse.startedAt(), lessonResponse.endedAt(), lessonResponse.record()); + } } diff --git a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java index fb3fe1b..c2c012c 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java @@ -1,5 +1,6 @@ package org.doochul.domain.lesson; +import org.doochul.domain.product.Product; import org.springframework.data.jpa.repository.JpaRepository; import java.time.LocalDateTime; @@ -9,6 +10,7 @@ public interface LessonRepository extends JpaRepository { default Lesson getById(final Long id) { return findById(id).orElseThrow(() -> new IllegalArgumentException("해당 수업이 없습니다.")); } - + List findByUserId(Long userId); List findByStartedAtBefore(final LocalDateTime currentServerTime); + } diff --git a/doochul/src/main/java/org/doochul/ui/LessonController.java b/doochul/src/main/java/org/doochul/ui/LessonController.java new file mode 100644 index 0000000..79be02a --- /dev/null +++ b/doochul/src/main/java/org/doochul/ui/LessonController.java @@ -0,0 +1,26 @@ +package org.doochul.ui; + +import lombok.RequiredArgsConstructor; +import org.doochul.application.LessonService; +import org.doochul.application.ProductService; +import org.doochul.ui.dto.LessonResponse; +import org.doochul.ui.dto.ProductResponse; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.net.URI; +import java.util.List; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/lesson") +public class LessonController { + + private final LessonService lessonService; + + @PostMapping("/save") + public ResponseEntity save(final Long userId, @RequestBody LessonResponse lessonResponse) { + Long lessonId = lessonService.save(userId, lessonResponse); + return ResponseEntity.created(URI.create("/lesson/"+ lessonId)).build(); + } +} diff --git a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java new file mode 100644 index 0000000..43886cc --- /dev/null +++ b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java @@ -0,0 +1,33 @@ +package org.doochul.ui.dto; + +import lombok.Builder; +import org.doochul.domain.lesson.Lesson; +import org.doochul.domain.membership.MemberShip; +import org.doochul.domain.user.User; + +import java.time.LocalDateTime; +import java.util.List; + +public record LessonResponse( + Long id, + MemberShip memberShip, + User student, + User teacher, + LocalDateTime startedAt, + LocalDateTime endedAt, + String record +) { + public static LessonResponse from(Lesson lesson) { + return new LessonResponse(lesson.getId(), lesson.getMemberShip(), lesson.getStudent(), + lesson.getTeacher(), lesson.getStartedAt(), lesson.getEndedAt(),lesson.getRecord()); + } + + public static List fromList(List lessons) { + return lessons.stream() + .map(LessonResponse::from) + .toList(); + } + + + +} From c355f71b48df87f42fe0401e11240475d09b36cb Mon Sep 17 00:00:00 2001 From: yukudaa Date: Mon, 18 Mar 2024 17:54:14 +0900 Subject: [PATCH 07/15] feat/16-create-lesson --- .../java/org/doochul/domain/product/ProductRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java b/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java index d5a3e8e..00f8401 100644 --- a/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java +++ b/doochul/src/main/java/org/doochul/domain/product/ProductRepository.java @@ -1,10 +1,13 @@ package org.doochul.domain.product; import java.util.List; + +import org.doochul.domain.user.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface ProductRepository extends JpaRepository { List findAll(); + List findByUserId(Long userId); } From 7f7c56924ab7bb1c6bb66a7a026fc42f416a01a1 Mon Sep 17 00:00:00 2001 From: yukudaa Date: Tue, 26 Mar 2024 16:49:29 +0900 Subject: [PATCH 08/15] feat/16-create-lesson --- .../main/java/org/doochul/application/LessonService.java | 5 ----- .../src/main/java/org/doochul/domain/lesson/Lesson.java | 8 ++++---- .../java/org/doochul/domain/lesson/LessonRepository.java | 2 +- .../src/main/java/org/doochul/ui/dto/LessonResponse.java | 4 ++-- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/doochul/src/main/java/org/doochul/application/LessonService.java b/doochul/src/main/java/org/doochul/application/LessonService.java index 547e060..4dcd074 100644 --- a/doochul/src/main/java/org/doochul/application/LessonService.java +++ b/doochul/src/main/java/org/doochul/application/LessonService.java @@ -16,11 +16,6 @@ public class LessonService { private final LessonRepository lessonRepository; private final UserRepository userRepository; - public List findMemberShipsById(Long userId) { - List lessons = lessonRepository.findByUserId(userId); - return LessonResponse.fromList(lessons); - } - public Long save(final Long userId, final LessonResponse lessonResponse) { final User user = userRepository.findById(userId).orElseThrow(); return lessonRepository.save(Lesson.of(user,lessonResponse)).getId(); diff --git a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java index 437e6ce..b6d4c32 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java @@ -31,8 +31,8 @@ public class Lesson extends BaseEntity { private MemberShip memberShip; @ManyToOne - @JoinColumn(name = "student_id") - private User student; + @JoinColumn(name = "general_id") + private User general; @ManyToOne @JoinColumn(name = "teacher_id") @@ -44,10 +44,10 @@ public class Lesson extends BaseEntity { private String record; - private Lesson(Long id, MemberShip memberShip, User student, User teacher, LocalDateTime startedAt, LocalDateTime endedAt, String record) { + private Lesson(Long id, MemberShip memberShip, User general, User teacher, LocalDateTime startedAt, LocalDateTime endedAt, String record) { this.id = id; this.memberShip = memberShip; - this.student = student; + this.general = general; this.teacher = teacher; this.startedAt = startedAt; this.endedAt = endedAt; diff --git a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java index c2c012c..ed5cdc0 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java @@ -10,7 +10,7 @@ public interface LessonRepository extends JpaRepository { default Lesson getById(final Long id) { return findById(id).orElseThrow(() -> new IllegalArgumentException("해당 수업이 없습니다.")); } - List findByUserId(Long userId); + //List findByUserId(Long userId); List findByStartedAtBefore(final LocalDateTime currentServerTime); } diff --git a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java index 43886cc..c5dde39 100644 --- a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java +++ b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java @@ -11,14 +11,14 @@ public record LessonResponse( Long id, MemberShip memberShip, - User student, + User general, User teacher, LocalDateTime startedAt, LocalDateTime endedAt, String record ) { public static LessonResponse from(Lesson lesson) { - return new LessonResponse(lesson.getId(), lesson.getMemberShip(), lesson.getStudent(), + return new LessonResponse(lesson.getId(), lesson.getMemberShip(), lesson.getGeneral(), lesson.getTeacher(), lesson.getStartedAt(), lesson.getEndedAt(),lesson.getRecord()); } From 8082eb8c65aeff5555b2bf1a02217c2502b3334e Mon Sep 17 00:00:00 2001 From: yukudaa Date: Wed, 27 Mar 2024 13:36:01 +0900 Subject: [PATCH 09/15] feat/16-save-lesson --- .../org/doochul/application/LessonService.java | 17 ++++++++++++----- .../java/org/doochul/domain/lesson/Lesson.java | 18 ++++-------------- .../domain/lesson/LessonRepository.java | 3 ++- .../java/org/doochul/ui/LessonController.java | 18 +++++++++--------- .../java/org/doochul/ui/dto/LessonRequest.java | 16 ++++++++++++++++ .../org/doochul/ui/dto/LessonResponse.java | 9 +++------ 6 files changed, 46 insertions(+), 35 deletions(-) create mode 100644 doochul/src/main/java/org/doochul/ui/dto/LessonRequest.java diff --git a/doochul/src/main/java/org/doochul/application/LessonService.java b/doochul/src/main/java/org/doochul/application/LessonService.java index 4dcd074..466e3b8 100644 --- a/doochul/src/main/java/org/doochul/application/LessonService.java +++ b/doochul/src/main/java/org/doochul/application/LessonService.java @@ -3,10 +3,15 @@ import lombok.RequiredArgsConstructor; import org.doochul.domain.lesson.Lesson; import org.doochul.domain.lesson.LessonRepository; +import org.doochul.domain.membership.MemberShip; +import org.doochul.domain.membership.MemberShipRepository; import org.doochul.domain.user.User; import org.doochul.domain.user.UserRepository; -import org.doochul.ui.dto.LessonResponse; +import org.doochul.ui.dto.LessonRequest; + import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import java.util.List; @Service @@ -14,11 +19,13 @@ public class LessonService { private final LessonRepository lessonRepository; - private final UserRepository userRepository; + private final MemberShipRepository memberShipRepository; - public Long save(final Long userId, final LessonResponse lessonResponse) { - final User user = userRepository.findById(userId).orElseThrow(); - return lessonRepository.save(Lesson.of(user,lessonResponse)).getId(); + @Transactional + // request 받아서 save 하는 로직 + public Long save(final Long membershipId, final LessonRequest lessonRequest) { + final MemberShip memberShip = memberShipRepository.findById(membershipId).orElseThrow(); + return lessonRepository.save(Lesson.of(memberShip, lessonRequest.getStartedAt(), lessonRequest.getEndedAt(), lessonRequest.getRecord())).getId(); } diff --git a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java index b6d4c32..09c9c88 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java @@ -15,6 +15,7 @@ import org.doochul.domain.BaseEntity; import org.doochul.domain.membership.MemberShip; import org.doochul.domain.user.User; +import org.doochul.ui.dto.LessonRequest; import org.doochul.ui.dto.LessonResponse; @Entity @@ -30,31 +31,20 @@ public class Lesson extends BaseEntity { @JoinColumn(name = "membership_id") private MemberShip memberShip; - @ManyToOne - @JoinColumn(name = "general_id") - private User general; - - @ManyToOne - @JoinColumn(name = "teacher_id") - private User teacher; - private LocalDateTime startedAt; private LocalDateTime endedAt; private String record; - private Lesson(Long id, MemberShip memberShip, User general, User teacher, LocalDateTime startedAt, LocalDateTime endedAt, String record) { + public Lesson(Long id, MemberShip memberShip, LocalDateTime startedAt, LocalDateTime endedAt, String record) { this.id = id; this.memberShip = memberShip; - this.general = general; - this.teacher = teacher; this.startedAt = startedAt; this.endedAt = endedAt; this.record = record; } - - public static Lesson of(User user,LessonResponse lessonResponse) { - return new Lesson(lessonResponse.id(), lessonResponse.memberShip(), user, user,lessonResponse.startedAt(), lessonResponse.endedAt(), lessonResponse.record()); + public static Lesson of(MemberShip memberShip, LocalDateTime startedAt, LocalDateTime endedAt, String record) { + return new Lesson(null, memberShip,startedAt,endedAt,record); } } diff --git a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java index ed5cdc0..b2fc77b 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/LessonRepository.java @@ -2,15 +2,16 @@ import org.doochul.domain.product.Product; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; import java.time.LocalDateTime; import java.util.List; +@Repository public interface LessonRepository extends JpaRepository { default Lesson getById(final Long id) { return findById(id).orElseThrow(() -> new IllegalArgumentException("해당 수업이 없습니다.")); } - //List findByUserId(Long userId); List findByStartedAtBefore(final LocalDateTime currentServerTime); } diff --git a/doochul/src/main/java/org/doochul/ui/LessonController.java b/doochul/src/main/java/org/doochul/ui/LessonController.java index 79be02a..98ff921 100644 --- a/doochul/src/main/java/org/doochul/ui/LessonController.java +++ b/doochul/src/main/java/org/doochul/ui/LessonController.java @@ -2,14 +2,15 @@ import lombok.RequiredArgsConstructor; import org.doochul.application.LessonService; -import org.doochul.application.ProductService; +import org.doochul.domain.lesson.Lesson; +import org.doochul.domain.user.User; + +import org.doochul.ui.dto.LessonRequest; import org.doochul.ui.dto.LessonResponse; -import org.doochul.ui.dto.ProductResponse; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.net.URI; -import java.util.List; + @RestController @RequiredArgsConstructor @@ -17,10 +18,9 @@ public class LessonController { private final LessonService lessonService; - - @PostMapping("/save") - public ResponseEntity save(final Long userId, @RequestBody LessonResponse lessonResponse) { - Long lessonId = lessonService.save(userId, lessonResponse); - return ResponseEntity.created(URI.create("/lesson/"+ lessonId)).build(); + @PostMapping("/save/{membershipId}") + public Long save(final @PathVariable Long membershipId, final @RequestBody LessonRequest lessonRequest) { + return lessonService.save(membershipId,lessonRequest); } + } diff --git a/doochul/src/main/java/org/doochul/ui/dto/LessonRequest.java b/doochul/src/main/java/org/doochul/ui/dto/LessonRequest.java new file mode 100644 index 0000000..52f74e2 --- /dev/null +++ b/doochul/src/main/java/org/doochul/ui/dto/LessonRequest.java @@ -0,0 +1,16 @@ +package org.doochul.ui.dto; + +import lombok.Getter; +import org.doochul.domain.lesson.Lesson; +import org.doochul.domain.membership.MemberShip; +import org.doochul.domain.user.User; + +import java.time.LocalDateTime; + +@Getter +public class LessonRequest { + private LocalDateTime startedAt; + private LocalDateTime endedAt; + private String record; + +} diff --git a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java index c5dde39..508f458 100644 --- a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java +++ b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java @@ -11,18 +11,15 @@ public record LessonResponse( Long id, MemberShip memberShip, - User general, - User teacher, LocalDateTime startedAt, LocalDateTime endedAt, String record ) { - public static LessonResponse from(Lesson lesson) { - return new LessonResponse(lesson.getId(), lesson.getMemberShip(), lesson.getGeneral(), - lesson.getTeacher(), lesson.getStartedAt(), lesson.getEndedAt(),lesson.getRecord()); + public static LessonResponse from(final Lesson lesson) { + return new LessonResponse(lesson.getId(), lesson.getMemberShip(), lesson.getStartedAt(), lesson.getEndedAt(),lesson.getRecord()); } - public static List fromList(List lessons) { + public static List fromList(final List lessons) { return lessons.stream() .map(LessonResponse::from) .toList(); From 63cbc46da21d4c366dae858ce69510ec9ec44972 Mon Sep 17 00:00:00 2001 From: yukudaa Date: Wed, 27 Mar 2024 14:40:35 +0900 Subject: [PATCH 10/15] feat/16-create-lesson --- .../java/org/doochul/application/LessonService.java | 8 -------- .../main/java/org/doochul/domain/lesson/Lesson.java | 6 ++---- .../main/java/org/doochul/ui/LessonController.java | 12 ++---------- .../main/java/org/doochul/ui/dto/LessonResponse.java | 5 +---- 4 files changed, 5 insertions(+), 26 deletions(-) diff --git a/doochul/src/main/java/org/doochul/application/LessonService.java b/doochul/src/main/java/org/doochul/application/LessonService.java index 466e3b8..883fa33 100644 --- a/doochul/src/main/java/org/doochul/application/LessonService.java +++ b/doochul/src/main/java/org/doochul/application/LessonService.java @@ -5,15 +5,10 @@ import org.doochul.domain.lesson.LessonRepository; import org.doochul.domain.membership.MemberShip; import org.doochul.domain.membership.MemberShipRepository; -import org.doochul.domain.user.User; -import org.doochul.domain.user.UserRepository; import org.doochul.ui.dto.LessonRequest; - import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; - @Service @RequiredArgsConstructor public class LessonService { @@ -22,11 +17,8 @@ public class LessonService { private final MemberShipRepository memberShipRepository; @Transactional - // request 받아서 save 하는 로직 public Long save(final Long membershipId, final LessonRequest lessonRequest) { final MemberShip memberShip = memberShipRepository.findById(membershipId).orElseThrow(); return lessonRepository.save(Lesson.of(memberShip, lessonRequest.getStartedAt(), lessonRequest.getEndedAt(), lessonRequest.getRecord())).getId(); } - - } diff --git a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java index 09c9c88..4f490fd 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java @@ -14,9 +14,6 @@ import lombok.NoArgsConstructor; import org.doochul.domain.BaseEntity; import org.doochul.domain.membership.MemberShip; -import org.doochul.domain.user.User; -import org.doochul.ui.dto.LessonRequest; -import org.doochul.ui.dto.LessonResponse; @Entity @Getter @@ -44,7 +41,8 @@ public Lesson(Long id, MemberShip memberShip, LocalDateTime startedAt, LocalDate this.endedAt = endedAt; this.record = record; } + public static Lesson of(MemberShip memberShip, LocalDateTime startedAt, LocalDateTime endedAt, String record) { - return new Lesson(null, memberShip,startedAt,endedAt,record); + return new Lesson(null, memberShip, startedAt, endedAt, record); } } diff --git a/doochul/src/main/java/org/doochul/ui/LessonController.java b/doochul/src/main/java/org/doochul/ui/LessonController.java index 98ff921..ce2fe74 100644 --- a/doochul/src/main/java/org/doochul/ui/LessonController.java +++ b/doochul/src/main/java/org/doochul/ui/LessonController.java @@ -2,25 +2,17 @@ import lombok.RequiredArgsConstructor; import org.doochul.application.LessonService; -import org.doochul.domain.lesson.Lesson; -import org.doochul.domain.user.User; - import org.doochul.ui.dto.LessonRequest; -import org.doochul.ui.dto.LessonResponse; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; - - @RestController @RequiredArgsConstructor @RequestMapping("/lesson") public class LessonController { - private final LessonService lessonService; + @PostMapping("/save/{membershipId}") public Long save(final @PathVariable Long membershipId, final @RequestBody LessonRequest lessonRequest) { - return lessonService.save(membershipId,lessonRequest); + return lessonService.save(membershipId, lessonRequest); } - } diff --git a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java index 508f458..0450c2a 100644 --- a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java +++ b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java @@ -16,7 +16,7 @@ public record LessonResponse( String record ) { public static LessonResponse from(final Lesson lesson) { - return new LessonResponse(lesson.getId(), lesson.getMemberShip(), lesson.getStartedAt(), lesson.getEndedAt(),lesson.getRecord()); + return new LessonResponse(lesson.getId(), lesson.getMemberShip(), lesson.getStartedAt(), lesson.getEndedAt(), lesson.getRecord()); } public static List fromList(final List lessons) { @@ -24,7 +24,4 @@ public static List fromList(final List lessons) { .map(LessonResponse::from) .toList(); } - - - } From 1d0e4a6ce3594a9690a06b62c358f49719370efb Mon Sep 17 00:00:00 2001 From: yukudaa Date: Wed, 27 Mar 2024 15:18:28 +0900 Subject: [PATCH 11/15] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A9=94=EC=86=8C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/doochul/ui/dto/LessonResponse.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java index 0450c2a..cbd0d86 100644 --- a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java +++ b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java @@ -18,10 +18,4 @@ public record LessonResponse( public static LessonResponse from(final Lesson lesson) { return new LessonResponse(lesson.getId(), lesson.getMemberShip(), lesson.getStartedAt(), lesson.getEndedAt(), lesson.getRecord()); } - - public static List fromList(final List lessons) { - return lessons.stream() - .map(LessonResponse::from) - .toList(); - } } From 595a665f61e56bc16badd17237b6a3d673640e29 Mon Sep 17 00:00:00 2001 From: yukudaa Date: Wed, 27 Mar 2024 15:36:12 +0900 Subject: [PATCH 12/15] =?UTF-8?q?feat:=20record=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/doochul/ui/dto/LessonRequest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doochul/src/main/java/org/doochul/ui/dto/LessonRequest.java b/doochul/src/main/java/org/doochul/ui/dto/LessonRequest.java index 52f74e2..aa296ca 100644 --- a/doochul/src/main/java/org/doochul/ui/dto/LessonRequest.java +++ b/doochul/src/main/java/org/doochul/ui/dto/LessonRequest.java @@ -7,10 +7,10 @@ import java.time.LocalDateTime; -@Getter -public class LessonRequest { - private LocalDateTime startedAt; - private LocalDateTime endedAt; - private String record; +public record LessonRequest( + LocalDateTime startedAt, + LocalDateTime endedAt, + String record +) { } From 74c3cc759b884c3e14a3111181b8597d84cecf82 Mon Sep 17 00:00:00 2001 From: yukudaa Date: Sat, 30 Mar 2024 20:26:43 +0900 Subject: [PATCH 13/15] =?UTF-8?q?feat:=20Lesson=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doochul/application/LessonService.java | 12 ++++++++++-- .../java/org/doochul/domain/lesson/Lesson.java | 17 ++++++++++++++--- .../java/org/doochul/ui/LessonController.java | 4 ++-- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/doochul/src/main/java/org/doochul/application/LessonService.java b/doochul/src/main/java/org/doochul/application/LessonService.java index 883fa33..4385ca0 100644 --- a/doochul/src/main/java/org/doochul/application/LessonService.java +++ b/doochul/src/main/java/org/doochul/application/LessonService.java @@ -5,6 +5,10 @@ import org.doochul.domain.lesson.LessonRepository; import org.doochul.domain.membership.MemberShip; import org.doochul.domain.membership.MemberShipRepository; +import org.doochul.domain.product.Product; +import org.doochul.domain.product.ProductRepository; +import org.doochul.domain.user.User; +import org.doochul.domain.user.UserRepository; import org.doochul.ui.dto.LessonRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -15,10 +19,14 @@ public class LessonService { private final LessonRepository lessonRepository; private final MemberShipRepository memberShipRepository; + private final UserRepository userRepository; + private final ProductRepository productRepository; @Transactional - public Long save(final Long membershipId, final LessonRequest lessonRequest) { + public Long save(final Long userId, final Long membershipId, final LessonRequest lessonRequest) { + final User user = userRepository.findById(userId).orElseThrow(); final MemberShip memberShip = memberShipRepository.findById(membershipId).orElseThrow(); - return lessonRepository.save(Lesson.of(memberShip, lessonRequest.getStartedAt(), lessonRequest.getEndedAt(), lessonRequest.getRecord())).getId(); + + return lessonRepository.save(Lesson.of(user, memberShip.getProduct().getTeacher(),memberShip, lessonRequest.startedAt(), lessonRequest.endedAt(), lessonRequest.record())).getId(); } } diff --git a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java index 4f490fd..57a0516 100644 --- a/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java +++ b/doochul/src/main/java/org/doochul/domain/lesson/Lesson.java @@ -14,6 +14,7 @@ import lombok.NoArgsConstructor; import org.doochul.domain.BaseEntity; import org.doochul.domain.membership.MemberShip; +import org.doochul.domain.user.User; @Entity @Getter @@ -28,21 +29,31 @@ public class Lesson extends BaseEntity { @JoinColumn(name = "membership_id") private MemberShip memberShip; + @ManyToOne + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne + @JoinColumn(name = "teacher_id") + private User teacher; + private LocalDateTime startedAt; private LocalDateTime endedAt; private String record; - public Lesson(Long id, MemberShip memberShip, LocalDateTime startedAt, LocalDateTime endedAt, String record) { + private Lesson(Long id, User user, User teacher, MemberShip memberShip, LocalDateTime startedAt, LocalDateTime endedAt, String record) { this.id = id; + this.user = user; + this.teacher = teacher; this.memberShip = memberShip; this.startedAt = startedAt; this.endedAt = endedAt; this.record = record; } - public static Lesson of(MemberShip memberShip, LocalDateTime startedAt, LocalDateTime endedAt, String record) { - return new Lesson(null, memberShip, startedAt, endedAt, record); + public static Lesson of(User user, User teacher, MemberShip memberShip, LocalDateTime startedAt, LocalDateTime endedAt, String record) { + return new Lesson(null, user, teacher,memberShip, startedAt, endedAt, record); } } diff --git a/doochul/src/main/java/org/doochul/ui/LessonController.java b/doochul/src/main/java/org/doochul/ui/LessonController.java index ce2fe74..bcd1fcc 100644 --- a/doochul/src/main/java/org/doochul/ui/LessonController.java +++ b/doochul/src/main/java/org/doochul/ui/LessonController.java @@ -12,7 +12,7 @@ public class LessonController { private final LessonService lessonService; @PostMapping("/save/{membershipId}") - public Long save(final @PathVariable Long membershipId, final @RequestBody LessonRequest lessonRequest) { - return lessonService.save(membershipId, lessonRequest); + public Long save(@AuthenticationPrincipal Long userId, @PathVariable final Long membershipId, @RequestBody final LessonRequest lessonRequest) { + return lessonService.save(userId, membershipId, lessonRequest); } } From f69fc5dee0dd9d31da9b6d6a1f23c592a5779c27 Mon Sep 17 00:00:00 2001 From: yukudaa Date: Sat, 30 Mar 2024 20:28:38 +0900 Subject: [PATCH 14/15] =?UTF-8?q?feat:=20Lesson=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/doochul/ui/dto/LessonResponse.java | 21 ------------------- 1 file changed, 21 deletions(-) delete mode 100644 doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java diff --git a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java b/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java deleted file mode 100644 index cbd0d86..0000000 --- a/doochul/src/main/java/org/doochul/ui/dto/LessonResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.doochul.ui.dto; - -import lombok.Builder; -import org.doochul.domain.lesson.Lesson; -import org.doochul.domain.membership.MemberShip; -import org.doochul.domain.user.User; - -import java.time.LocalDateTime; -import java.util.List; - -public record LessonResponse( - Long id, - MemberShip memberShip, - LocalDateTime startedAt, - LocalDateTime endedAt, - String record -) { - public static LessonResponse from(final Lesson lesson) { - return new LessonResponse(lesson.getId(), lesson.getMemberShip(), lesson.getStartedAt(), lesson.getEndedAt(), lesson.getRecord()); - } -} From d23599c98769ec3fa10a0825bca4ea2f2036e387 Mon Sep 17 00:00:00 2001 From: yukudaa Date: Sat, 30 Mar 2024 20:30:03 +0900 Subject: [PATCH 15/15] =?UTF-8?q?feat:=20LessonService=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doochul/src/main/java/org/doochul/application/LessonService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/doochul/src/main/java/org/doochul/application/LessonService.java b/doochul/src/main/java/org/doochul/application/LessonService.java index 4385ca0..c112a3b 100644 --- a/doochul/src/main/java/org/doochul/application/LessonService.java +++ b/doochul/src/main/java/org/doochul/application/LessonService.java @@ -20,7 +20,6 @@ public class LessonService { private final LessonRepository lessonRepository; private final MemberShipRepository memberShipRepository; private final UserRepository userRepository; - private final ProductRepository productRepository; @Transactional public Long save(final Long userId, final Long membershipId, final LessonRequest lessonRequest) {