From f7eb6cc95d6fa7c52b0a1e6117cc51c333ef6e03 Mon Sep 17 00:00:00 2001 From: Michal Vanko Date: Sun, 24 Nov 2024 14:56:54 +0100 Subject: [PATCH] Logic for recommended articles --- src/pages/blog_post_page.rs | 67 ++++++++++++++++++++++++++++--------- templates/blog_post.html | 15 ++++++++- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/pages/blog_post_page.rs b/src/pages/blog_post_page.rs index c101e8c..f425008 100644 --- a/src/pages/blog_post_page.rs +++ b/src/pages/blog_post_page.rs @@ -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, pub tags: Vec, - pub segment: String, + pub segment: Segment, pub header_props: HeaderProps, pub slug: String, pub thumbnail: Option, + pub recommended_posts: Vec>, } pub async fn render_blog_post( @@ -29,22 +32,27 @@ pub async fn render_blog_post( OriginalUri(original_uri): OriginalUri, ) -> Result { let path = format!("{}/{}.md", BLOG_POST_PATH, post_id); - let parse_post = parse_post::(&path); - let parsed = parse_post.await?; + let post = parse_post::(&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::>(); + 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>, StatusCode> { + let posts = get_post_list::(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::>(); + + Ok(recommended_posts) +} diff --git a/templates/blog_post.html b/templates/blog_post.html index 72b55fd..6651f0c 100644 --- a/templates/blog_post.html +++ b/templates/blog_post.html @@ -33,7 +33,20 @@ - + {# footer #} + {% endblock %}