diff --git a/src/lib/blog/BlogController.test.ts b/src/lib/blog/BlogController.test.ts index f725d54..3cf4da7 100644 --- a/src/lib/blog/BlogController.test.ts +++ b/src/lib/blog/BlogController.test.ts @@ -29,6 +29,25 @@ describe(`BlogController`, () => { }); }); + describe(`getBlogPostBySlug`, () => { + it(`should return null when the post doesn't exist`, async () => { + // When + const shouldBeNull = await controller.getBlogPostBySlug('some-made-up-blog-post'); + + // Then + expect(shouldBeNull).toBeNull(); + }); + + it(`should return the blog post when it exists`, async () => { + // When + const blogPost = await controller.getBlogPostBySlug('2023-02-03-vibe-check-10'); + + // Then + expect(blogPost).not.toBeNull(); + expect(blogPost.title).toBe('Vibe Check #10'); + }); + }); + describe(`Finding content by slug`, () => { describe(`Finding a blog post`, () => { // GIVEN diff --git a/src/lib/blog/BlogController.ts b/src/lib/blog/BlogController.ts index 46fff0f..0804924 100644 --- a/src/lib/blog/BlogController.ts +++ b/src/lib/blog/BlogController.ts @@ -9,6 +9,7 @@ interface BlogItem { content: string; slug: string; content_type: 'blog' | 'book_review' | 'snout_street_studios'; + tags?: string[]; } interface BlogPostListItem extends BlogItem { @@ -17,6 +18,7 @@ interface BlogPostListItem extends BlogItem { date: string; book_review: boolean; preview: string; + tags: string[]; } interface BookReviewListItem extends BlogItem { @@ -95,6 +97,45 @@ export class BlogController { return allBlogPosts.slice(0, pageSize); } + async getBlogPostBySlug(slug: string): Promise { + const blogPost = await this._markdownRepository.getBlogPostBySlug(slug); + if (blogPost) { + return this.blogPostToBlogPostListItem(blogPost); + } + + return null; + } + + async getBlogPostsByTags(tags: string[]): Promise { + const posts = await this.getAllBlogPosts(); + const blogPosts = posts.filter((post) => post.content_type === 'blog') as BlogPostListItem[]; + return blogPosts + .filter((post: BlogPostListItem) => post['tags']?.length > 0) + .filter((post: BlogPostListItem) => (post.tags as string[]).some((tag) => tags.includes(tag))); + } + + async getAnyKindOfContentBySlug( + slug: string + ): Promise { + const blogPost = await this._markdownRepository.getBlogPostBySlug(slug); + if (blogPost) { + return this.blogPostToBlogPostListItem(blogPost); + } + + const bookReview = await this._markdownRepository.getBookReviewBySlug(slug); + if (bookReview) { + return this.bookReviewToBookReviewListItem(bookReview); + } + + const snoutStreetStudiosPost = await this._markdownRepository.getSnoutStreetStudiosPostBySlug(slug); + + if (snoutStreetStudiosPost) { + return this.snoutStreetStudiosPostToSnoutStreetStudiosPostListItem(snoutStreetStudiosPost); + } + + return null; + } + private bookReviewToBookReviewListItem(bookReview: BookReview): BookReviewListItem { return { book_review: true, @@ -120,6 +161,7 @@ export class BlogController { preview: blogPost.excerpt, slug: blogPost.slug, content_type: 'blog', + tags: blogPost.tags, }; } @@ -134,26 +176,4 @@ export class BlogController { content: post.html, }; } - - async getAnyKindOfContentBySlug( - slug: string - ): Promise { - const blogPost = await this._markdownRepository.getBlogPostBySlug(slug); - if (blogPost) { - return this.blogPostToBlogPostListItem(blogPost); - } - - const bookReview = await this._markdownRepository.getBookReviewBySlug(slug); - if (bookReview) { - return this.bookReviewToBookReviewListItem(bookReview); - } - - const snoutStreetStudiosPost = await this._markdownRepository.getSnoutStreetStudiosPostBySlug(slug); - - if (snoutStreetStudiosPost) { - return this.snoutStreetStudiosPostToSnoutStreetStudiosPostListItem(snoutStreetStudiosPost); - } - - return null; - } } diff --git a/src/lib/blog/markdown-repository.ts b/src/lib/blog/markdown-repository.ts index 3671160..f1cddee 100644 --- a/src/lib/blog/markdown-repository.ts +++ b/src/lib/blog/markdown-repository.ts @@ -19,6 +19,7 @@ interface BlogPostFrontmatterValues { slug: string; date: Date; author: string; + tags?: string[]; } interface BookReviewFrontmatterValues { @@ -55,6 +56,7 @@ export class MarkdownRepository { public static async singleton(forceRefresh = false): Promise { if (forceRefresh || !this._singleton) { + console.log(`[MarkdownRepository::singleton] Building MarkdownRepository singleton.`); this._singleton = await MarkdownRepository.fromViteGlobImport( blogPostMetaGlobImport, bookReviewsMetaGlobImport, @@ -90,7 +92,7 @@ export class MarkdownRepository { author: markdownFile.frontmatter.author, date: markdownFile.frontmatter.date, fileName: filename, - tags: [], + tags: markdownFile.frontmatter.tags, }); fileImports = [...fileImports, markdownFile]; diff --git a/src/lib/snout-street-studios/ApiGateway.ts b/src/lib/snout-street-studios/ApiGateway.ts index a238e7d..9939ffe 100644 --- a/src/lib/snout-street-studios/ApiGateway.ts +++ b/src/lib/snout-street-studios/ApiGateway.ts @@ -17,6 +17,7 @@ export class SnoutStreetStudiosApiGateway { title: post.title, html: post.content, toJson: () => JSON.stringify(post), + excerpt: post. }; } }