feat: Add tags to BlogPosts and allow posts to be found with them
This commit is contained in:
parent
26ecb457b7
commit
5ca7fc1ced
4 changed files with 65 additions and 23 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<BlogPostListItem | null> {
|
||||
const blogPost = await this._markdownRepository.getBlogPostBySlug(slug);
|
||||
if (blogPost) {
|
||||
return this.blogPostToBlogPostListItem(blogPost);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
async getBlogPostsByTags(tags: string[]): Promise<BlogPostListItem[]> {
|
||||
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<BookReviewListItem | BlogPostListItem | SnoutStreetStudiosPostListItem | null> {
|
||||
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<BookReviewListItem | BlogPostListItem | SnoutStreetStudiosPostListItem | null> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<MarkdownRepository> {
|
||||
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];
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export class SnoutStreetStudiosApiGateway {
|
|||
title: post.title,
|
||||
html: post.content,
|
||||
toJson: () => JSON.stringify(post),
|
||||
excerpt: post.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue