Simplify related articles: shared article header, ids only, no job
- Both article pages render one `_article_head.html` partial from an `ArticleHead` built by a single constructor instead of two copies. - `related::for_article` returns ids; the cosine stays stored for tuning. - Title keys travel with each candidate, dropping the side map. - Drop the `related-refresh` dashboard job: the backfill is a one-off and `features related` covers it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AeJmv3WED4w8S3GV7mMjS7
This commit is contained in:
1 parent
03f0a454be
commit
08b15c42b4
7 files changed
+79
-143
No files matched your search
+45
-49
@@ -943,19 +943,8 @@ struct ArticleLink {
|
||||
struct ArticleTemplate {
|
||||
page: Page,
|
||||
toc: Toc,
|
||||
title: String,
|
||||
source_url: String,
|
||||
byline: Option<String>,
|
||||
source: Source,
|
||||
meta_line: String,
|
||||
social_line: Option<String>,
|
||||
understanding: chapters::Understanding,
|
||||
summary: Option<String>,
|
||||
excerpt_only: bool,
|
||||
body_html: String,
|
||||
head: ArticleHead,
|
||||
discussion_html: Option<String>,
|
||||
read_online_url: String,
|
||||
dashboard_href: String,
|
||||
rating: Option<RatingWidget>,
|
||||
previous: Option<ArticleLink>,
|
||||
next: Option<ArticleLink>,
|
||||
@@ -969,18 +958,50 @@ struct ArticleTemplate {
|
||||
#[template(path = "article_standalone.html")]
|
||||
struct StandaloneArticleTemplate {
|
||||
page: Page,
|
||||
head: ArticleHead,
|
||||
}
|
||||
|
||||
/// What `_article_head.html` renders (header and body) plus the footer links
|
||||
/// both article pages share.
|
||||
struct ArticleHead {
|
||||
title: String,
|
||||
source_url: String,
|
||||
byline: Option<String>,
|
||||
source: Source,
|
||||
meta_line: String,
|
||||
social_line: Option<String>,
|
||||
/// Issue-only: empty and `None` on the standalone page.
|
||||
understanding: chapters::Understanding,
|
||||
summary: Option<String>,
|
||||
excerpt_only: bool,
|
||||
body_html: String,
|
||||
read_online_url: String,
|
||||
dashboard_href: String,
|
||||
}
|
||||
|
||||
impl ArticleHead {
|
||||
fn new(article: &Article, config: &Config, is_admin: bool) -> Self {
|
||||
Self {
|
||||
title: article.title.clone(),
|
||||
source_url: article.canonical_url.clone(),
|
||||
byline: article.author.as_ref().map(|author| format!("By {author}")),
|
||||
source: Source::new(article, config, is_admin),
|
||||
meta_line: format!(
|
||||
"{} words · ~{} min read",
|
||||
thousands(article.word_count),
|
||||
article.reading_minutes()
|
||||
),
|
||||
social_line: chapters::social_line(&article.social),
|
||||
understanding: chapters::Understanding::default(),
|
||||
summary: None,
|
||||
excerpt_only: article.excerpt_only,
|
||||
body_html: prepare_body(&article.content_html),
|
||||
read_online_url: article.url.clone(),
|
||||
dashboard_href: format!("/dashboard/articles/{}", article.id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// One entry of the "Related" list under an issue article.
|
||||
#[derive(Debug)]
|
||||
struct RelatedView {
|
||||
@@ -1150,26 +1171,15 @@ pub async fn article(
|
||||
Ok(Html(ArticleTemplate {
|
||||
page,
|
||||
toc,
|
||||
title: article.title.clone(),
|
||||
source_url: article.canonical_url.clone(),
|
||||
byline: article.author.as_ref().map(|author| format!("By {author}")),
|
||||
source: Source::new(article, &config, is_admin),
|
||||
meta_line: format!(
|
||||
"{} words · ~{} min read",
|
||||
thousands(article.word_count),
|
||||
article.reading_minutes()
|
||||
),
|
||||
social_line: chapters::social_line(&article.social),
|
||||
understanding: chapters::understanding(pick),
|
||||
summary: summary_for(&view.issue, pick).map(str::to_string),
|
||||
excerpt_only: article.excerpt_only,
|
||||
body_html: prepare_body(&article.content_html),
|
||||
head: ArticleHead {
|
||||
understanding: chapters::understanding(pick),
|
||||
summary: summary_for(&view.issue, pick).map(str::to_string),
|
||||
..ArticleHead::new(article, &config, is_admin)
|
||||
},
|
||||
discussion_html: pick
|
||||
.discussion
|
||||
.as_ref()
|
||||
.map(|discussion| crate::comments::render_xhtml(discussion, &article.title)),
|
||||
read_online_url: article.url.clone(),
|
||||
dashboard_href: format!("/dashboard/articles/{}", article.id),
|
||||
rating: is_admin.then(|| {
|
||||
RatingWidget::for_issue(
|
||||
article.id,
|
||||
@@ -1217,20 +1227,7 @@ pub async fn standalone(
|
||||
page.flash = take_flash(&session).await?;
|
||||
Ok(Html(StandaloneArticleTemplate {
|
||||
page,
|
||||
title: article.title.clone(),
|
||||
source_url: article.canonical_url.clone(),
|
||||
byline: article.author.as_ref().map(|author| format!("By {author}")),
|
||||
source: Source::new(&article, &config, is_admin),
|
||||
meta_line: format!(
|
||||
"{} words · ~{} min read",
|
||||
thousands(article.word_count),
|
||||
article.reading_minutes()
|
||||
),
|
||||
social_line: chapters::social_line(&article.social),
|
||||
excerpt_only: article.excerpt_only,
|
||||
body_html: prepare_body(&article.content_html),
|
||||
read_online_url: article.url.clone(),
|
||||
dashboard_href: format!("/dashboard/articles/{}", article.id),
|
||||
head: ArticleHead::new(&article, &config, is_admin),
|
||||
})
|
||||
.into_response())
|
||||
}
|
||||
@@ -1244,18 +1241,17 @@ async fn related_views(
|
||||
date: Date,
|
||||
article_id: ArticleId,
|
||||
) -> anyhow::Result<Vec<RelatedView>> {
|
||||
let links = crate::related::for_article(db, date, article_id).await?;
|
||||
if links.is_empty() {
|
||||
let ids = crate::related::for_article(db, date, article_id).await?;
|
||||
if ids.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
let ids: Vec<ArticleId> = links.iter().map(|link| link.article_id).collect();
|
||||
let articles = db.get_articles(&ids).await?;
|
||||
let issues = crate::related::latest_issues(db, &ids).await?;
|
||||
Ok(links
|
||||
Ok(ids
|
||||
.iter()
|
||||
.filter_map(|link| {
|
||||
let article = articles.get(&link.article_id)?;
|
||||
let href = match issues.get(&link.article_id) {
|
||||
.filter_map(|id| {
|
||||
let article = articles.get(id)?;
|
||||
let href = match issues.get(id) {
|
||||
Some(date) => article_href(*date, article.id),
|
||||
None => standalone_href(article.id),
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user