From: Felix Ableitner <me@nutomic.com>
Date: Fri, 20 Nov 2020 14:11:47 +0000 (+0100)
Subject: Generate valid RSS feed (fixes #1274)
X-Git-Url: http://these/git/readmes/%7Bpost.ap_id%7D?a=commitdiff_plain;h=8920f439ce6ebc17300618cfc53dedae0ac047aa;p=lemmy.git

Generate valid RSS feed (fixes #1274)
---

diff --git a/src/lib.rs b/src/lib.rs
index 7e5754d4..e6ea900e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,5 @@
 #![recursion_limit = "512"]
-
+#[macro_use]
+extern crate lazy_static;
 pub mod code_migrations;
 pub mod routes;
diff --git a/src/routes/feeds.rs b/src/routes/feeds.rs
index 303a824b..a9454be4 100644
--- a/src/routes/feeds.rs
+++ b/src/routes/feeds.rs
@@ -16,9 +16,15 @@ use lemmy_db::{
 use lemmy_structs::blocking;
 use lemmy_utils::{settings::Settings, utils::markdown_to_html, LemmyError};
 use lemmy_websocket::LemmyContext;
-use rss::{CategoryBuilder, ChannelBuilder, GuidBuilder, Item, ItemBuilder};
+use rss::{
+  extension::dublincore::DublinCoreExtensionBuilder,
+  ChannelBuilder,
+  GuidBuilder,
+  Item,
+  ItemBuilder,
+};
 use serde::Deserialize;
-use std::str::FromStr;
+use std::{collections::HashMap, str::FromStr};
 use strum::ParseError;
 
 #[derive(Deserialize)]
@@ -39,6 +45,17 @@ pub fn config(cfg: &mut web::ServiceConfig) {
     .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(
   info: web::Query<Params>,
   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();
   channel_builder
+    .namespaces(RSS_NAMESPACE.to_owned())
     .title(&format!("{} - All", site_view.name))
     .link(Settings::get().get_protocol_and_hostname())
     .items(items);
@@ -141,6 +159,7 @@ fn get_feed_user(
 
   let mut channel_builder = ChannelBuilder::default();
   channel_builder
+    .namespaces(RSS_NAMESPACE.to_owned())
     .title(&format!("{} - {}", site_view.name, user.name))
     .link(user_url)
     .items(items);
@@ -166,6 +185,7 @@ fn get_feed_community(
 
   let mut channel_builder = ChannelBuilder::default();
   channel_builder
+    .namespaces(RSS_NAMESPACE.to_owned())
     .title(&format!("{} - {}", site_view.name, community.name))
     .link(community.actor_id)
     .items(items);
@@ -195,6 +215,7 @@ fn get_feed_front(
 
   let mut channel_builder = ChannelBuilder::default();
   channel_builder
+    .namespaces(RSS_NAMESPACE.to_owned())
     .title(&format!("{} - Subscribed", site_view.name))
     .link(Settings::get().get_protocol_and_hostname())
     .items(items);
@@ -224,6 +245,7 @@ fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, Le
 
   let mut channel_builder = ChannelBuilder::default();
   channel_builder
+    .namespaces(RSS_NAMESPACE.to_owned())
     .title(&format!("{} - Inbox", site_view.name))
     .link(format!(
       "{}/inbox",
@@ -310,18 +332,11 @@ fn create_post_items(posts: Vec<PostView>) -> Result<Vec<Item>, LemmyError> {
 
   for p in posts {
     let mut i = ItemBuilder::default();
+    let mut dc_extension = DublinCoreExtensionBuilder::default();
 
     i.title(p.name);
 
-    let author_url = format!(
-      "{}/u/{}",
-      Settings::get().get_protocol_and_hostname(),
-      p.creator_name
-    );
-    i.author(format!(
-      "/u/{} <a href=\"{}\">(link)</a>",
-      p.creator_name, author_url
-    ));
+    dc_extension.creators(vec![p.creator_actor_id.to_owned()]);
 
     let dt = DateTime::<Utc>::from_utc(p.published, Utc);
     i.pub_date(dt.to_rfc2822());
@@ -345,16 +360,8 @@ fn create_post_items(posts: Vec<PostView>) -> Result<Vec<Item>, LemmyError> {
       p.community_name
     );
 
-    let category = CategoryBuilder::default()
-      .name(format!(
-        "/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]);
+    // TODO: for category we should just put the name of the category, but then we would have
+    //       to read each community from the db
 
     if let Some(url) = p.url {
       i.link(url);
@@ -362,7 +369,7 @@ fn create_post_items(posts: Vec<PostView>) -> Result<Vec<Item>, LemmyError> {
 
     // TODO add images
     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,
     community_url,
     p.community_name,
@@ -377,6 +384,7 @@ fn create_post_items(posts: Vec<PostView>) -> Result<Vec<Item>, LemmyError> {
 
     i.description(description);
 
+    i.dublin_core_ext(dc_extension.build().map_err(|e| anyhow!(e))?);
     items.push(i.build().map_err(|e| anyhow!(e))?);
   }