Generate valid RSS feed (fixes #1274)

pull/1281/head
Felix Ableitner 2020-11-20 15:11:47 +01:00
parent 405ea38959
commit 8920f439ce
2 changed files with 32 additions and 23 deletions

View File

@ -1,4 +1,5 @@
#![recursion_limit = "512"] #![recursion_limit = "512"]
#[macro_use]
extern crate lazy_static;
pub mod code_migrations; pub mod code_migrations;
pub mod routes; pub mod routes;

View File

@ -16,9 +16,15 @@ use lemmy_db::{
use lemmy_structs::blocking; use lemmy_structs::blocking;
use lemmy_utils::{settings::Settings, utils::markdown_to_html, LemmyError}; use lemmy_utils::{settings::Settings, utils::markdown_to_html, LemmyError};
use lemmy_websocket::LemmyContext; use lemmy_websocket::LemmyContext;
use rss::{CategoryBuilder, ChannelBuilder, GuidBuilder, Item, ItemBuilder}; use rss::{
extension::dublincore::DublinCoreExtensionBuilder,
ChannelBuilder,
GuidBuilder,
Item,
ItemBuilder,
};
use serde::Deserialize; use serde::Deserialize;
use std::str::FromStr; use std::{collections::HashMap, str::FromStr};
use strum::ParseError; use strum::ParseError;
#[derive(Deserialize)] #[derive(Deserialize)]
@ -39,6 +45,17 @@ pub fn config(cfg: &mut web::ServiceConfig) {
.route("/feeds/all.xml", web::get().to(get_all_feed)); .route("/feeds/all.xml", web::get().to(get_all_feed));
} }
lazy_static! {
static ref RSS_NAMESPACE: HashMap<String, String> = {
let mut h = HashMap::new();
h.insert(
"dc".to_string(),
rss::extension::dublincore::NAMESPACE.to_string(),
);
h
};
}
async fn get_all_feed( async fn get_all_feed(
info: web::Query<Params>, info: web::Query<Params>,
context: web::Data<LemmyContext>, context: web::Data<LemmyContext>,
@ -70,6 +87,7 @@ fn get_feed_all_data(conn: &PgConnection, sort_type: &SortType) -> Result<String
let mut channel_builder = ChannelBuilder::default(); let mut channel_builder = ChannelBuilder::default();
channel_builder channel_builder
.namespaces(RSS_NAMESPACE.to_owned())
.title(&format!("{} - All", site_view.name)) .title(&format!("{} - All", site_view.name))
.link(Settings::get().get_protocol_and_hostname()) .link(Settings::get().get_protocol_and_hostname())
.items(items); .items(items);
@ -141,6 +159,7 @@ fn get_feed_user(
let mut channel_builder = ChannelBuilder::default(); let mut channel_builder = ChannelBuilder::default();
channel_builder channel_builder
.namespaces(RSS_NAMESPACE.to_owned())
.title(&format!("{} - {}", site_view.name, user.name)) .title(&format!("{} - {}", site_view.name, user.name))
.link(user_url) .link(user_url)
.items(items); .items(items);
@ -166,6 +185,7 @@ fn get_feed_community(
let mut channel_builder = ChannelBuilder::default(); let mut channel_builder = ChannelBuilder::default();
channel_builder channel_builder
.namespaces(RSS_NAMESPACE.to_owned())
.title(&format!("{} - {}", site_view.name, community.name)) .title(&format!("{} - {}", site_view.name, community.name))
.link(community.actor_id) .link(community.actor_id)
.items(items); .items(items);
@ -195,6 +215,7 @@ fn get_feed_front(
let mut channel_builder = ChannelBuilder::default(); let mut channel_builder = ChannelBuilder::default();
channel_builder channel_builder
.namespaces(RSS_NAMESPACE.to_owned())
.title(&format!("{} - Subscribed", site_view.name)) .title(&format!("{} - Subscribed", site_view.name))
.link(Settings::get().get_protocol_and_hostname()) .link(Settings::get().get_protocol_and_hostname())
.items(items); .items(items);
@ -224,6 +245,7 @@ fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, Le
let mut channel_builder = ChannelBuilder::default(); let mut channel_builder = ChannelBuilder::default();
channel_builder channel_builder
.namespaces(RSS_NAMESPACE.to_owned())
.title(&format!("{} - Inbox", site_view.name)) .title(&format!("{} - Inbox", site_view.name))
.link(format!( .link(format!(
"{}/inbox", "{}/inbox",
@ -310,18 +332,11 @@ fn create_post_items(posts: Vec<PostView>) -> Result<Vec<Item>, LemmyError> {
for p in posts { for p in posts {
let mut i = ItemBuilder::default(); let mut i = ItemBuilder::default();
let mut dc_extension = DublinCoreExtensionBuilder::default();
i.title(p.name); i.title(p.name);
let author_url = format!( dc_extension.creators(vec![p.creator_actor_id.to_owned()]);
"{}/u/{}",
Settings::get().get_protocol_and_hostname(),
p.creator_name
);
i.author(format!(
"/u/{} <a href=\"{}\">(link)</a>",
p.creator_name, author_url
));
let dt = DateTime::<Utc>::from_utc(p.published, Utc); let dt = DateTime::<Utc>::from_utc(p.published, Utc);
i.pub_date(dt.to_rfc2822()); i.pub_date(dt.to_rfc2822());
@ -345,16 +360,8 @@ fn create_post_items(posts: Vec<PostView>) -> Result<Vec<Item>, LemmyError> {
p.community_name p.community_name
); );
let category = CategoryBuilder::default() // TODO: for category we should just put the name of the category, but then we would have
.name(format!( // to read each community from the db
"/c/{} <a href=\"{}\">(link)</a>",
p.community_name, community_url
))
.domain(Settings::get().hostname.to_owned())
.build()
.map_err(|e| anyhow!(e))?;
i.categories(vec![category]);
if let Some(url) = p.url { if let Some(url) = p.url {
i.link(url); i.link(url);
@ -362,7 +369,7 @@ fn create_post_items(posts: Vec<PostView>) -> Result<Vec<Item>, LemmyError> {
// TODO add images // TODO add images
let mut description = format!("submitted by <a href=\"{}\">{}</a> to <a href=\"{}\">{}</a><br>{} points | <a href=\"{}\">{} comments</a>", let mut description = format!("submitted by <a href=\"{}\">{}</a> to <a href=\"{}\">{}</a><br>{} points | <a href=\"{}\">{} comments</a>",
author_url, p.creator_actor_id,
p.creator_name, p.creator_name,
community_url, community_url,
p.community_name, p.community_name,
@ -377,6 +384,7 @@ fn create_post_items(posts: Vec<PostView>) -> Result<Vec<Item>, LemmyError> {
i.description(description); i.description(description);
i.dublin_core_ext(dc_extension.build().map_err(|e| anyhow!(e))?);
items.push(i.build().map_err(|e| anyhow!(e))?); items.push(i.build().map_err(|e| anyhow!(e))?);
} }