diff --git a/application/usecases/saveBookSuggestionForBookClubUseCase/saveBookSuggestionForBookClubUseCase.ts b/application/usecases/saveBookSuggestionForBookClubUseCase/saveBookSuggestionForBookClubUseCase.ts new file mode 100644 index 0000000..b486b53 --- /dev/null +++ b/application/usecases/saveBookSuggestionForBookClubUseCase/saveBookSuggestionForBookClubUseCase.ts @@ -0,0 +1,35 @@ +import ChatService from "../../../domain/service/chatService"; +import SaveBookSuggestionForBookClubUseCaseInput from "./saveBookSuggestionForBookClubUseCaseInput"; +import BookSuggestionsRepository from "../../../domain/repository/bookSuggestionsRepository"; +import BookSuggestion from "../../../domain/entity/bookSuggestion"; + +export default class SaveBookSuggestionForBookClubUseCase { + private bookSuggestionsRepository: BookSuggestionsRepository; + + private chatService: ChatService; + + constructor({ + chatService, + bookSuggestionsRepository, + }: { + chatService: ChatService; + bookSuggestionsRepository: BookSuggestionsRepository; + }) { + this.chatService = chatService; + this.bookSuggestionsRepository = bookSuggestionsRepository; + } + + async execute({ title, link, channelId }: SaveBookSuggestionForBookClubUseCaseInput): Promise { + const bookSuggestionAlreadyExists = this.bookSuggestionsRepository.findByTitle(title); + if (bookSuggestionAlreadyExists) { + this.chatService.sendMessageToChannel( + `Infelizmente o conteúdo **"${title}"** já tinha sido sugerido.`, + channelId + ); + return; + } + + this.bookSuggestionsRepository.add(new BookSuggestion({ title, link })); + this.chatService.sendMessageToChannel(`A sugestão **"${title}"** foi enviada.`, channelId); + } +} diff --git a/application/usecases/saveBookSuggestionForBookClubUseCase/saveBookSuggestionForBookClubUseCaseInput.ts b/application/usecases/saveBookSuggestionForBookClubUseCase/saveBookSuggestionForBookClubUseCaseInput.ts new file mode 100644 index 0000000..1fa31fa --- /dev/null +++ b/application/usecases/saveBookSuggestionForBookClubUseCase/saveBookSuggestionForBookClubUseCaseInput.ts @@ -0,0 +1,5 @@ +export default interface SaveBookSuggestionForBookClubUseCaseInput { + title: string; + link: string; + channelId: string; +} diff --git a/domain/entity/bookSuggestion.ts b/domain/entity/bookSuggestion.ts new file mode 100644 index 0000000..744728c --- /dev/null +++ b/domain/entity/bookSuggestion.ts @@ -0,0 +1,18 @@ +export default class BookSuggestion { + private readonly title: string; + + private readonly link: string; + + constructor({ title, link }: { title: string; link: string }) { + this.title = title; + this.link = link; + } + + getTitle(): string { + return this.title; + } + + getLink(): string { + return this.link; + } +} diff --git a/domain/repository/bookSuggestionsRepository.ts b/domain/repository/bookSuggestionsRepository.ts new file mode 100644 index 0000000..1fddfa0 --- /dev/null +++ b/domain/repository/bookSuggestionsRepository.ts @@ -0,0 +1,6 @@ +import BookSuggestion from "../entity/bookSuggestion"; + +export default interface BookSuggestionsRepository { + add(bookSuggestion: BookSuggestion): void; + findByTitle(title: string): BookSuggestion | null; +} diff --git a/vitest/application/usecases/saveBookSuggestionForBookClubUseCase.spec.ts b/vitest/application/usecases/saveBookSuggestionForBookClubUseCase.spec.ts new file mode 100644 index 0000000..9b0fc8f --- /dev/null +++ b/vitest/application/usecases/saveBookSuggestionForBookClubUseCase.spec.ts @@ -0,0 +1,87 @@ +import { vi, describe, it, expect } from "vitest"; +import SaveBookSuggestionForBookClubUseCase from "../../../application/usecases/saveBookSuggestionForBookClubUseCase/saveBookSuggestionForBookClubUseCase"; +import BookSuggestion from "../../../domain/entity/bookSuggestion"; + +describe("send book suggestion for book club use case", () => { + it("should save in book suggestions repository the suggested book", async () => { + const bookSuggestionsRepository = { + add: vi.fn(), + findByTitle: vi.fn(), + }; + + const chatService = { + sendMessageToChannel: vi.fn(), + }; + + await new SaveBookSuggestionForBookClubUseCase({ + bookSuggestionsRepository, + chatService, + }).execute({ + title: "The Lord of the Rings", + link: "https://www.amazon.com/Lord-Rings-1-3-J-R-R-Tolkien/dp/0618260307", + channelId: "855861944930402342", + }); + + expect(bookSuggestionsRepository.add).toHaveBeenCalledWith({ + title: "The Lord of the Rings", + link: "https://www.amazon.com/Lord-Rings-1-3-J-R-R-Tolkien/dp/0618260307", + }); + }); + + it("should send a message from chatService thanking the user", async () => { + const bookSuggestionsRepository = { + add: vi.fn(), + findByTitle: vi.fn(), + }; + + const chatService = { + sendMessageToChannel: vi.fn(), + }; + + const spy = vi.spyOn(chatService, "sendMessageToChannel"); + + await new SaveBookSuggestionForBookClubUseCase({ + bookSuggestionsRepository, + chatService, + }).execute({ + title: "The Lord of the Rings", + link: "https://www.amazon.com/Lord-Rings-1-3-J-R-R-Tolkien/dp/0618260307", + channelId: "855861944930402342", + }); + + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith('A sugestão **"The Lord of the Rings"** foi enviada.', "855861944930402342"); + }); + + it("should send a message from chatService in case the book was already suggested", async () => { + const bookSuggestionsRepository = { + add: vi.fn(), + findByTitle: () => + new BookSuggestion({ + title: "The Lord of the Rings", + link: "https://www.amazon.com/Lord-Rings-1-3-J-R-R-Tolkien/dp/0618260307", + }), + }; + + const chatService = { + sendMessageToChannel: vi.fn(), + }; + + const spy = vi.spyOn(chatService, "sendMessageToChannel"); + + await new SaveBookSuggestionForBookClubUseCase({ + bookSuggestionsRepository, + chatService, + }).execute({ + title: "The Lord of the Rings", + link: "https://www.amazon.com/Lord-Rings-1-3-J-R-R-Tolkien/dp/0618260307", + channelId: "855861944930402342", + }); + + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toHaveBeenCalledWith( + 'Infelizmente o conteúdo **"The Lord of the Rings"** já tinha sido sugerido.', + "855861944930402342" + ); + }); +});