feat: Add tags to BlogPosts and allow posts to be found with them

This commit is contained in:
Thomas 2025-03-13 21:42:06 +00:00
parent 26ecb457b7
commit 5ca7fc1ced
No known key found for this signature in database
4 changed files with 65 additions and 23 deletions

View file

@ -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

View file

@ -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;
}
}

View file

@ -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];

View file

@ -17,6 +17,7 @@ export class SnoutStreetStudiosApiGateway {
title: post.title,
html: post.content,
toJson: () => JSON.stringify(post),
excerpt: post.
};
}
}