Logic for recommended articles
This commit is contained in:
parent
fec60900f5
commit
f7eb6cc95d
@ -3,7 +3,9 @@ use axum::extract::OriginalUri;
|
||||
use axum::{extract::Path, http::StatusCode};
|
||||
use chrono::{DateTime, Utc};
|
||||
|
||||
use crate::blog_posts::blog_post_model::BLOG_POST_PATH;
|
||||
use crate::blog_posts::blog_post_model::{Segment, BLOG_POST_PATH};
|
||||
use crate::post_utils::post_listing::get_post_list;
|
||||
use crate::post_utils::post_parser::ParseResult;
|
||||
use crate::{
|
||||
blog_posts::blog_post_model::BlogPostMetadata, components::site_header::Link, filters,
|
||||
post_utils::post_parser::parse_post,
|
||||
@ -18,10 +20,11 @@ pub struct BlogPostTemplate {
|
||||
pub body: String,
|
||||
pub date: DateTime<Utc>,
|
||||
pub tags: Vec<String>,
|
||||
pub segment: String,
|
||||
pub segment: Segment,
|
||||
pub header_props: HeaderProps,
|
||||
pub slug: String,
|
||||
pub thumbnail: Option<String>,
|
||||
pub recommended_posts: Vec<ParseResult<BlogPostMetadata>>,
|
||||
}
|
||||
|
||||
pub async fn render_blog_post(
|
||||
@ -29,22 +32,27 @@ pub async fn render_blog_post(
|
||||
OriginalUri(original_uri): OriginalUri,
|
||||
) -> Result<BlogPostTemplate, StatusCode> {
|
||||
let path = format!("{}/{}.md", BLOG_POST_PATH, post_id);
|
||||
let parse_post = parse_post::<BlogPostMetadata>(&path);
|
||||
let parsed = parse_post.await?;
|
||||
let post = parse_post::<BlogPostMetadata>(&path).await?;
|
||||
let segment = if original_uri.to_string().starts_with("/blog") {
|
||||
"blog"
|
||||
Segment::Blog
|
||||
} else if original_uri.to_string().starts_with("/broadcasts") {
|
||||
"broadcasts"
|
||||
Segment::Broadcasts
|
||||
} else {
|
||||
"blog"
|
||||
Segment::Blog
|
||||
};
|
||||
|
||||
let mut recommended_posts = get_recommended_posts(&segment, &post.metadata.tags).await?;
|
||||
recommended_posts.retain(|post| post.slug != post_id);
|
||||
recommended_posts.sort_by_key(|post| post.slug.to_string());
|
||||
recommended_posts.reverse();
|
||||
let recommended_posts = recommended_posts.into_iter().take(2).collect::<Vec<_>>();
|
||||
|
||||
let header_props = match segment {
|
||||
"blog" => HeaderProps::with_back_link(Link {
|
||||
Segment::Blog => HeaderProps::with_back_link(Link {
|
||||
href: "/blog".to_string(),
|
||||
label: "All posts".to_string(),
|
||||
}),
|
||||
"broadcasts" => HeaderProps::with_back_link(Link {
|
||||
Segment::Broadcasts => HeaderProps::with_back_link(Link {
|
||||
href: "/broadcasts".to_string(),
|
||||
label: "All broadcasts".to_string(),
|
||||
}),
|
||||
@ -52,13 +60,40 @@ pub async fn render_blog_post(
|
||||
};
|
||||
|
||||
Ok(BlogPostTemplate {
|
||||
title: parsed.metadata.title,
|
||||
date: parsed.metadata.date,
|
||||
tags: parsed.metadata.tags,
|
||||
body: parsed.body,
|
||||
slug: parsed.slug,
|
||||
segment: segment.to_string(),
|
||||
thumbnail: parsed.metadata.thumbnail,
|
||||
title: post.metadata.title,
|
||||
date: post.metadata.date,
|
||||
tags: post.metadata.tags,
|
||||
body: post.body,
|
||||
slug: post.slug,
|
||||
segment,
|
||||
thumbnail: post.metadata.thumbnail,
|
||||
header_props,
|
||||
recommended_posts,
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_recommended_posts(
|
||||
segment: &Segment,
|
||||
tags: &[String],
|
||||
) -> Result<Vec<ParseResult<BlogPostMetadata>>, StatusCode> {
|
||||
let posts = get_post_list::<BlogPostMetadata>(BLOG_POST_PATH).await?;
|
||||
|
||||
let recommended_posts = posts
|
||||
.into_iter()
|
||||
.filter(|post| {
|
||||
let is_same_segment = post
|
||||
.metadata
|
||||
.segments
|
||||
.iter()
|
||||
.any(|post_segment| post_segment == segment);
|
||||
let has_same_tags = post
|
||||
.metadata
|
||||
.tags
|
||||
.iter()
|
||||
.any(|post_tag| tags.contains(post_tag));
|
||||
is_same_segment && has_same_tags
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(recommended_posts)
|
||||
}
|
||||
|
@ -33,7 +33,20 @@
|
||||
</article>
|
||||
|
||||
<!-- TODO: Next recommendations for reading -->
|
||||
<!-- TODO: Bact to all posts -->
|
||||
<!-- TODO: Back to all posts -->
|
||||
|
||||
{# footer #}
|
||||
<footer>
|
||||
<hr class="border-slate-300 m-5 md:my-8">
|
||||
|
||||
<ul class="mx-5">
|
||||
{% for post in recommended_posts %}
|
||||
<li>
|
||||
{% include "components/blog_post_preview.html" %}
|
||||
<!-- TODO hidden block media -->
|
||||
<hr class="border-slate-300 my-5 md:my-8 hidden lg:block">
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</footer>
|
||||
{% endblock %}
|
||||
|
Loading…
Reference in New Issue
Block a user