feat: add title param to render_feed, use dynamic title in RSS adapter
This commit is contained in:
@@ -14,11 +14,11 @@ impl RssAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RssFeedRenderer for RssAdapter {
|
impl RssFeedRenderer for RssAdapter {
|
||||||
fn render_feed(&self, entries: &[DiaryEntry]) -> Result<String, String> {
|
fn render_feed(&self, entries: &[DiaryEntry], title: &str) -> Result<String, String> {
|
||||||
let items = entries
|
let items = entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|e| {
|
.map(|e| {
|
||||||
let title = format!(
|
let item_title = format!(
|
||||||
"{} ({})",
|
"{} ({})",
|
||||||
e.movie().title().value(),
|
e.movie().title().value(),
|
||||||
e.movie().release_year().value()
|
e.movie().release_year().value()
|
||||||
@@ -38,7 +38,7 @@ impl RssFeedRenderer for RssAdapter {
|
|||||||
.permalink(false)
|
.permalink(false)
|
||||||
.build();
|
.build();
|
||||||
ItemBuilder::default()
|
ItemBuilder::default()
|
||||||
.title(Some(title))
|
.title(Some(item_title))
|
||||||
.description(Some(description))
|
.description(Some(description))
|
||||||
.pub_date(Some(pub_date))
|
.pub_date(Some(pub_date))
|
||||||
.guid(Some(guid))
|
.guid(Some(guid))
|
||||||
@@ -47,12 +47,31 @@ impl RssFeedRenderer for RssAdapter {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let channel = ChannelBuilder::default()
|
let channel = ChannelBuilder::default()
|
||||||
.title(self.feed_title.clone())
|
.title(title.to_string())
|
||||||
.link(self.feed_link.clone())
|
.link(self.feed_link.clone())
|
||||||
.description(self.feed_title.clone())
|
.description(title.to_string())
|
||||||
.items(items)
|
.items(items)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Ok(channel.to_string())
|
Ok(channel.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_feed_uses_provided_title() {
|
||||||
|
let adapter = RssAdapter::new("ignored".into(), "http://example.com".into());
|
||||||
|
let xml = adapter.render_feed(&[], "Custom Title").unwrap();
|
||||||
|
assert!(xml.contains("<title>Custom Title</title>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn render_feed_empty_entries_produces_valid_xml() {
|
||||||
|
let adapter = RssAdapter::new("ignored".into(), "http://example.com".into());
|
||||||
|
let xml = adapter.render_feed(&[], "My Feed").unwrap();
|
||||||
|
assert!(xml.starts_with("<?xml") || xml.starts_with("<rss"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,5 +67,5 @@ pub trait HtmlRenderer: Send + Sync {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait RssFeedRenderer: Send + Sync {
|
pub trait RssFeedRenderer: Send + Sync {
|
||||||
fn render_feed(&self, entries: &[DiaryEntry]) -> Result<String, String>;
|
fn render_feed(&self, entries: &[DiaryEntry], title: &str) -> Result<String, String>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ mod tests {
|
|||||||
|
|
||||||
struct PanicRssRenderer;
|
struct PanicRssRenderer;
|
||||||
impl crate::ports::RssFeedRenderer for PanicRssRenderer {
|
impl crate::ports::RssFeedRenderer for PanicRssRenderer {
|
||||||
fn render_feed(&self, _: &[domain::models::DiaryEntry]) -> Result<String, String> { panic!() }
|
fn render_feed(&self, _: &[domain::models::DiaryEntry], _: &str) -> Result<String, String> { panic!() }
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PanicMeta; struct PanicFetcher; struct PanicStorage; struct PanicEvent; struct PanicHasher; struct PanicAuth; struct PanicUserRepo;
|
struct PanicMeta; struct PanicFetcher; struct PanicStorage; struct PanicEvent; struct PanicHasher; struct PanicAuth; struct PanicUserRepo;
|
||||||
@@ -269,7 +269,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
struct PanicRssRenderer2;
|
struct PanicRssRenderer2;
|
||||||
impl crate::ports::RssFeedRenderer for PanicRssRenderer2 {
|
impl crate::ports::RssFeedRenderer for PanicRssRenderer2 {
|
||||||
fn render_feed(&self, _: &[domain::models::DiaryEntry]) -> Result<String, String> { panic!() }
|
fn render_feed(&self, _: &[domain::models::DiaryEntry], _: &str) -> Result<String, String> { panic!() }
|
||||||
}
|
}
|
||||||
struct PanicAuth2;
|
struct PanicAuth2;
|
||||||
crate::state::AppState {
|
crate::state::AppState {
|
||||||
@@ -329,7 +329,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
struct PanicRssRenderer3;
|
struct PanicRssRenderer3;
|
||||||
impl crate::ports::RssFeedRenderer for PanicRssRenderer3 {
|
impl crate::ports::RssFeedRenderer for PanicRssRenderer3 {
|
||||||
fn render_feed(&self, _: &[domain::models::DiaryEntry]) -> Result<String, String> { panic!() }
|
fn render_feed(&self, _: &[domain::models::DiaryEntry], _: &str) -> Result<String, String> { panic!() }
|
||||||
}
|
}
|
||||||
crate::state::AppState {
|
crate::state::AppState {
|
||||||
app_ctx: AppContext {
|
app_ctx: AppContext {
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ pub mod rss {
|
|||||||
let page = get_diary::execute(&state.app_ctx, query).await?;
|
let page = get_diary::execute(&state.app_ctx, query).await?;
|
||||||
let xml = state
|
let xml = state
|
||||||
.rss_renderer
|
.rss_renderer
|
||||||
.render_feed(&page.items)
|
.render_feed(&page.items, "Movie Diary")
|
||||||
.map_err(|e| ApiError(DomainError::InfrastructureError(e)))?;
|
.map_err(|e| ApiError(DomainError::InfrastructureError(e)))?;
|
||||||
Ok(([(header::CONTENT_TYPE, "application/rss+xml; charset=utf-8")], xml))
|
Ok(([(header::CONTENT_TYPE, "application/rss+xml; charset=utf-8")], xml))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user