diff --git a/.gitignore b/.gitignore index dc57c96..452eb22 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,11 @@ out/ # Ignore Gradle GUI config gradle-app.setting +*.classpath +*.project +*.settings/ +applications/bin/ +src/backoffice/bin/ +src/mooc/bin/ +src/shared/bin/ + diff --git a/src/mooc/build.gradle b/src/mooc/build.gradle index 986f161..8786a31 100644 --- a/src/mooc/build.gradle +++ b/src/mooc/build.gradle @@ -1,3 +1,9 @@ dependencies { compile project(":src:shared") + + compileOnly 'org.projectlombok:lombok:1.18.16' + annotationProcessor 'org.projectlombok:lombok:1.18.16' + + testCompileOnly 'org.projectlombok:lombok:1.18.16' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.16' } diff --git a/src/mooc/main/tv/codely/mooc/notification/application/like/SendPushToSubscribersOnVideoLiked.java b/src/mooc/main/tv/codely/mooc/notification/application/like/SendPushToSubscribersOnVideoLiked.java new file mode 100644 index 0000000..ee14dfc --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/notification/application/like/SendPushToSubscribersOnVideoLiked.java @@ -0,0 +1,22 @@ +package tv.codely.mooc.notification.application.like; + +import tv.codely.mooc.video.domain.VideoLiked; +import tv.codely.shared.application.DomainEventSubscriber; + +public class SendPushToSubscribersOnVideoLiked implements DomainEventSubscriber { + @Override + public Class subscribedTo() { + return VideoLiked.class; + } + + @Override + public void consume(VideoLiked event) { + System.out.println( + String.format( + "Hey! User with ID <%s> liked video with title <%s>", + event.userId(), + event.title() + ) + ); + } +} diff --git a/src/mooc/main/tv/codely/mooc/notification/application/like/VideoLiker.java b/src/mooc/main/tv/codely/mooc/notification/application/like/VideoLiker.java new file mode 100644 index 0000000..5a3f9f1 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/notification/application/like/VideoLiker.java @@ -0,0 +1,24 @@ +package tv.codely.mooc.video.application.like; + +import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; +import tv.codely.mooc.shared.user.domain.UserId; +import tv.codely.mooc.video.domain.VideoLike; +import tv.codely.mooc.video.domain.VideoTitle; +import tv.codely.shared.domain.EventBus; + +@AllArgsConstructor +public final class VideoLiker { + private final EventBus eventBus; + + public void like(String rawTitle, String rawUserId) { + final var title = new VideoTitle(rawTitle); + final var userId = new UserId(rawUserId); + + final var videoLike = VideoLike.like(title, userId); + + eventBus.publish(videoLike.pullDomainEvents()); + } + + +} diff --git a/src/mooc/main/tv/codely/mooc/shared/user/domain/UserId.java b/src/mooc/main/tv/codely/mooc/shared/user/domain/UserId.java new file mode 100644 index 0000000..6101087 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/shared/user/domain/UserId.java @@ -0,0 +1,18 @@ +package tv.codely.mooc.shared.user.domain; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + + +@EqualsAndHashCode +@RequiredArgsConstructor +public final class UserId { + private final String value; + + public String value() { + return value; + } + +} diff --git a/src/mooc/main/tv/codely/mooc/video/application/publish/CurrentSeason.java b/src/mooc/main/tv/codely/mooc/video/application/publish/CurrentSeason.java new file mode 100644 index 0000000..ba2a12f --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/video/application/publish/CurrentSeason.java @@ -0,0 +1,25 @@ +package tv.codely.mooc.video.application.publish; + + + +import tv.codely.mooc.video.domain.Clock; + +public final class CurrentSeason { + private Clock clock; + + private static String seasons[] = { + "Winter", "Winter", "Spring", "Spring", "Summer", "Summer", // not precise but :) + "Summer", "Summer", "Fall", "Fall", "Winter", "Winter" + }; + + CurrentSeason(Clock clock) { + this.clock = clock; + } + + public String check() { + return seasons[ clock.now().getMonthValue() ]; + } + + + +} diff --git a/src/mooc/main/tv/codely/mooc/video/domain/Clock.java b/src/mooc/main/tv/codely/mooc/video/domain/Clock.java new file mode 100644 index 0000000..de07823 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/video/domain/Clock.java @@ -0,0 +1,9 @@ +package tv.codely.mooc.video.domain; + +import java.time.Instant; +import java.time.LocalDate; + +public interface Clock { + public LocalDate now(); + +} diff --git a/src/mooc/main/tv/codely/mooc/video/domain/VideoLike.java b/src/mooc/main/tv/codely/mooc/video/domain/VideoLike.java new file mode 100644 index 0000000..5b107d7 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/video/domain/VideoLike.java @@ -0,0 +1,21 @@ +package tv.codely.mooc.video.domain; + +import tv.codely.mooc.shared.user.domain.UserId; +import tv.codely.shared.domain.AggregateRoot; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class VideoLike extends AggregateRoot { + private final VideoTitle title; + private final UserId userId; + + public static VideoLike like(VideoTitle title, UserId userId) { + var videoLike = new VideoLike(title, userId); + + var videoLiked = new VideoLiked(title.value(), userId.value()); + + videoLike.record(videoLiked); + + return videoLike; + } +} diff --git a/src/mooc/main/tv/codely/mooc/video/domain/VideoLiked.java b/src/mooc/main/tv/codely/mooc/video/domain/VideoLiked.java new file mode 100644 index 0000000..5233a12 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/video/domain/VideoLiked.java @@ -0,0 +1,31 @@ +package tv.codely.mooc.video.domain; + + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import tv.codely.shared.domain.DomainEvent; + +@RequiredArgsConstructor +@EqualsAndHashCode +public final class VideoLiked implements DomainEvent { + private static final String FULL_QUALIFIED_EVENT_NAME = "codelytv.video.video.event.1.video.liked"; + + private final String title; + + private final String userId; + + public String title() { + return title; + } + + public String userId() { + return userId; + } + + + public String fullQualifiedEventName() { + return FULL_QUALIFIED_EVENT_NAME; + } +} \ No newline at end of file diff --git a/src/mooc/main/tv/codely/mooc/video/infrastructure/CurrentClock.java b/src/mooc/main/tv/codely/mooc/video/infrastructure/CurrentClock.java new file mode 100644 index 0000000..4f12959 --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/video/infrastructure/CurrentClock.java @@ -0,0 +1,14 @@ +package tv.codely.mooc.video.infrastructure; + +import java.time.LocalDate; + +import tv.codely.mooc.video.domain.Clock; + +public class CurrentClock implements Clock { + + @Override + public LocalDate now() { + return LocalDate.now(); + } + +} diff --git a/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoLikeCliController.java b/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoLikeCliController.java new file mode 100644 index 0000000..9da39df --- /dev/null +++ b/src/mooc/main/tv/codely/mooc/video/infrastructure/VideoLikeCliController.java @@ -0,0 +1,24 @@ +package tv.codely.mooc.video.infrastructure; + +import java.util.Set; + +import tv.codely.mooc.notification.application.like.SendPushToSubscribersOnVideoLiked; +import tv.codely.mooc.video.application.like.VideoLiker; +import tv.codely.shared.application.DomainEventSubscriber; +import tv.codely.shared.domain.EventBus; +import tv.codely.shared.infrastructure.bus.ReactorEventBus; + +public final class VideoLikeCliController { + + public static void main(String[] args) { + final Set subscribers = Set.of(new SendPushToSubscribersOnVideoLiked()); + final EventBus eventBus = new ReactorEventBus(subscribers); + final var videoLiker = new VideoLiker(eventBus); + + final var videoTitle = "\uD83C\uDF89 New YouTube.com/CodelyTV video title"; + final var userId = "06e8bb44-486c-41ec-8395-ead1288e5b37"; + + videoLiker.like(videoTitle, userId); + + } +} \ No newline at end of file diff --git a/src/mooc/test/tv/codely/mooc/video/application/like/VideoLikerShould.java b/src/mooc/test/tv/codely/mooc/video/application/like/VideoLikerShould.java new file mode 100644 index 0000000..5045a20 --- /dev/null +++ b/src/mooc/test/tv/codely/mooc/video/application/like/VideoLikerShould.java @@ -0,0 +1,28 @@ + +package tv.codely.mooc.video.application.like; + +import org.junit.jupiter.api.Test; +import tv.codely.mooc.video.domain.VideoLiked; +import tv.codely.shared.domain.EventBus; + +import java.util.List; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +final class VideoLikerShould { + @Test + void publish_the_video_liked_domain_event() { + final var eventBus = mock(EventBus.class); + final var videoLiker = new VideoLiker(eventBus); + + final var videoTitle = "\uD83C\uDF89 New YouTube.com/CodelyTV video title"; + final var userId = "This should be the video description \uD83D\uDE42"; + + videoLiker.like(videoTitle, userId); + + final var expectedVideoLiked = new VideoLiked(videoTitle, userId); + + verify(eventBus).publish(List.of(expectedVideoLiked)); + } +} \ No newline at end of file diff --git a/src/mooc/test/tv/codely/mooc/video/application/publish/CurrentSeasonShould.java b/src/mooc/test/tv/codely/mooc/video/application/publish/CurrentSeasonShould.java new file mode 100644 index 0000000..4c49e96 --- /dev/null +++ b/src/mooc/test/tv/codely/mooc/video/application/publish/CurrentSeasonShould.java @@ -0,0 +1,37 @@ +package tv.codely.mooc.video.application.publish; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.time.LocalDate; +import java.time.Month; + +import org.junit.jupiter.api.Test; + +import tv.codely.mooc.video.domain.Clock; +import tv.codely.mooc.video.infrastructure.CurrentClock; + +final class CurrentSeasonShould { + + @Test + void return_winter() { + final Clock clock = mock(CurrentClock.class); + final var currentSeason = new CurrentSeason(clock); + + when(clock.now()).thenReturn(LocalDate.of(2021, Month.JANUARY, 1)); + + assertEquals("Winter", currentSeason.check()); + } + + @Test + void return_summer() { + final Clock clock = mock(CurrentClock.class); + final var currentSeason = new CurrentSeason(clock); + + when(clock.now()).thenReturn(LocalDate.of(2021, Month.JUNE, 23)); + + assertEquals("Summer", currentSeason.check()); + } + +}