]> Untitled Git - lemmy.git/commitdiff
Convert md to html for feeds, try to deduplicate code
authorFelix <me@nutomic.com>
Sat, 28 Mar 2020 15:56:20 +0000 (16:56 +0100)
committerFelix <me@nutomic.com>
Sat, 28 Mar 2020 15:56:20 +0000 (16:56 +0100)
server/Cargo.lock
server/Cargo.toml
server/src/routes/feeds.rs

index f6ce6550773ab5ab3db294edffb0a98dfddbfd37..265abfc781c81137f8d4224d7fa1d81f33a6f5be 100644 (file)
@@ -1,5 +1,14 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
+[[package]]
+name = "Markdown-to-HTML-rs"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "regex 1.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "activitypub"
 version = "0.2.0"
@@ -1369,6 +1378,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 name = "lemmy_server"
 version = "0.0.1"
 dependencies = [
+ "Markdown-to-HTML-rs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "activitypub 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "actix 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "actix-files 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2823,6 +2833,7 @@ dependencies = [
 ]
 
 [metadata]
+"checksum Markdown-to-HTML-rs 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1a9bda9d68f643d9b63888996896ce5be873d0f22fe1c859bce84dd4bd4661b"
 "checksum activitypub 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d538a21b137ec0f63cc579ef4afa4ab13aa85b4f8af15a033683edd97c50718d"
 "checksum activitystreams-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "65608fdeae5eb05485d5b71a3d2242d76b2b7413608c196d47eb4dff3eed7b85"
 "checksum activitystreams-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c2a3958d240f40eff1f31b5f679a6e0d4ce2a16812886a3ec0164f3a2ca517"
index 156ccb87a5c783edd0f582fc2fc6e0de93728516..3803485b4d934bc77b977f171199f1e31850df3b 100644 (file)
@@ -36,3 +36,4 @@ config = "0.10.1"
 hjson = "0.8.2"
 percent-encoding = "2.1.0"
 isahc = "0.9"
+Markdown-to-HTML-rs = "0.1.0"
index ad0f28d5a14c8f9fbdec8f09cb8f89f9199aa444..c94a60d45a55dcfd12513642bfdb8cefb02e55bd 100644 (file)
@@ -10,7 +10,7 @@ use crate::db::user_mention_view::{UserMentionQueryBuilder, UserMentionView};
 use crate::db::{ListingType, SortType};
 use crate::Settings;
 use actix_web::{web, HttpResponse, Result};
-use chrono::{DateTime, Utc};
+use chrono::{DateTime, NaiveDateTime, Utc};
 use diesel::r2d2::{ConnectionManager, Pool};
 use diesel::PgConnection;
 use failure::Error;
@@ -18,6 +18,7 @@ use rss::{CategoryBuilder, ChannelBuilder, GuidBuilder, Item, ItemBuilder};
 use serde::Deserialize;
 use std::str::FromStr;
 use strum::ParseError;
+extern crate Markdown_to_HTML_rs;
 
 #[derive(Deserialize)]
 pub struct Params {
@@ -34,7 +35,6 @@ enum RequestType {
 pub fn config(cfg: &mut web::ServiceConfig) {
   cfg
     .route("/feeds/{type}/{name}.xml", web::get().to(feeds::get_feed))
-    .route("/feeds/all.xml", web::get().to(feeds::get_all_feed))
     .route("/feeds/all.xml", web::get().to(feeds::get_all_feed));
 }
 
@@ -44,9 +44,7 @@ async fn get_all_feed(
 ) -> Result<HttpResponse, actix_web::Error> {
   let res = web::block(move || {
     let conn = db.get()?;
-
-    let sort_type = get_sort_type(info)?;
-    get_feed_all_data(&conn, &sort_type)
+    get_feed_all_data(&conn, &get_sort_type(info)?)
   })
   .await
   .map(|rss| {
@@ -58,6 +56,29 @@ async fn get_all_feed(
   Ok(res)
 }
 
+fn get_feed_all_data(conn: &PgConnection, sort_type: &SortType) -> Result<String, failure::Error> {
+  let site_view = SiteView::read(&conn)?;
+
+  let posts = PostQueryBuilder::create(&conn)
+    .listing_type(ListingType::All)
+    .sort(sort_type)
+    .list()?;
+
+  let items = create_post_items(posts);
+
+  let mut channel_builder = ChannelBuilder::default();
+  channel_builder
+    .title(&format!("{} - All", site_view.name))
+    .link(format!("https://{}", Settings::get().hostname))
+    .items(items);
+
+  if let Some(site_desc) = site_view.description {
+    channel_builder.description(&site_desc);
+  }
+
+  Ok(channel_builder.build().unwrap().to_string())
+}
+
 async fn get_feed(
   path: web::Path<(String, String)>,
   info: web::Query<Params>,
@@ -86,6 +107,7 @@ async fn get_feed(
     }
   })
   .await
+  .map(|builder| builder.build().unwrap().to_string())
   .map(|rss| {
     HttpResponse::Ok()
       .content_type("application/rss+xml")
@@ -103,34 +125,11 @@ fn get_sort_type(info: web::Query<Params>) -> Result<SortType, ParseError> {
   SortType::from_str(&sort_query)
 }
 
-fn get_feed_all_data(conn: &PgConnection, sort_type: &SortType) -> Result<String, failure::Error> {
-  let site_view = SiteView::read(&conn)?;
-
-  let posts = PostQueryBuilder::create(&conn)
-    .listing_type(ListingType::All)
-    .sort(sort_type)
-    .list()?;
-
-  let items = create_post_items(posts);
-
-  let mut channel_builder = ChannelBuilder::default();
-  channel_builder
-    .title(&format!("{} - All", site_view.name))
-    .link(format!("https://{}", Settings::get().hostname))
-    .items(items);
-
-  if let Some(site_desc) = site_view.description {
-    channel_builder.description(&site_desc);
-  }
-
-  Ok(channel_builder.build().unwrap().to_string())
-}
-
 fn get_feed_user(
   conn: &PgConnection,
   sort_type: &SortType,
   user_name: String,
-) -> Result<String, Error> {
+) -> Result<ChannelBuilder, Error> {
   let site_view = SiteView::read(&conn)?;
   let user = User_::find_by_username(&conn, &user_name)?;
   let user_url = user.get_profile_url();
@@ -149,14 +148,14 @@ fn get_feed_user(
     .link(user_url)
     .items(items);
 
-  Ok(channel_builder.build().unwrap().to_string())
+  Ok(channel_builder)
 }
 
 fn get_feed_community(
   conn: &PgConnection,
   sort_type: &SortType,
   community_name: String,
-) -> Result<String, Error> {
+) -> Result<ChannelBuilder, Error> {
   let site_view = SiteView::read(&conn)?;
   let community = Community::read_from_name(&conn, community_name)?;
   let community_url = community.get_url();
@@ -179,10 +178,14 @@ fn get_feed_community(
     channel_builder.description(&community_desc);
   }
 
-  Ok(channel_builder.build().unwrap().to_string())
+  Ok(channel_builder)
 }
 
-fn get_feed_front(conn: &PgConnection, sort_type: &SortType, jwt: String) -> Result<String, Error> {
+fn get_feed_front(
+  conn: &PgConnection,
+  sort_type: &SortType,
+  jwt: String,
+) -> Result<ChannelBuilder, Error> {
   let site_view = SiteView::read(&conn)?;
   let user_id = Claims::decode(&jwt)?.claims.id;
 
@@ -204,10 +207,10 @@ fn get_feed_front(conn: &PgConnection, sort_type: &SortType, jwt: String) -> Res
     channel_builder.description(&site_desc);
   }
 
-  Ok(channel_builder.build().unwrap().to_string())
+  Ok(channel_builder)
 }
 
-fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<String, Error> {
+fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<ChannelBuilder, Error> {
   let site_view = SiteView::read(&conn)?;
   let user_id = Claims::decode(&jwt)?.claims.id;
 
@@ -233,86 +236,61 @@ fn get_feed_inbox(conn: &PgConnection, jwt: String) -> Result<String, Error> {
     channel_builder.description(&site_desc);
   }
 
-  Ok(channel_builder.build().unwrap().to_string())
+  Ok(channel_builder)
 }
 
 fn create_reply_and_mention_items(
   replies: Vec<ReplyView>,
   mentions: Vec<UserMentionView>,
 ) -> Vec<Item> {
-  let mut items: Vec<Item> = Vec::new();
-
-  for r in replies {
-    let mut i = ItemBuilder::default();
-
-    i.title(format!("Reply from {}", r.creator_name));
-
-    let author_url = format!("https://{}/u/{}", Settings::get().hostname, r.creator_name);
-    i.author(format!(
-      "/u/{} <a href=\"{}\">(link)</a>",
-      r.creator_name, author_url
-    ));
-
-    let dt = DateTime::<Utc>::from_utc(r.published, Utc);
-    i.pub_date(dt.to_rfc2822());
-
-    let reply_url = format!(
-      "https://{}/post/{}/comment/{}",
-      Settings::get().hostname,
-      r.post_id,
-      r.id
-    );
-    i.comments(reply_url.to_owned());
-    let guid = GuidBuilder::default()
-      .permalink(true)
-      .value(&reply_url)
-      .build();
-    i.guid(guid.unwrap());
-
-    i.link(reply_url);
-
-    // TODO find a markdown to html parser here, do images, etc
-    i.description(r.content);
-
-    items.push(i.build().unwrap());
-  }
-
-  for m in mentions {
-    let mut i = ItemBuilder::default();
-
-    i.title(format!("Mention from {}", m.creator_name));
-
-    let author_url = format!("https://{}/u/{}", Settings::get().hostname, m.creator_name);
-    i.author(format!(
-      "/u/{} <a href=\"{}\">(link)</a>",
-      m.creator_name, author_url
-    ));
-
-    let dt = DateTime::<Utc>::from_utc(m.published, Utc);
-    i.pub_date(dt.to_rfc2822());
-
-    let mention_url = format!(
-      "https://{}/post/{}/comment/{}",
-      Settings::get().hostname,
-      m.post_id,
-      m.id
-    );
-    i.comments(mention_url.to_owned());
-    let guid = GuidBuilder::default()
-      .permalink(true)
-      .value(&mention_url)
-      .build();
-    i.guid(guid.unwrap());
-
-    i.link(mention_url);
-
-    // TODO find a markdown to html parser here, do images, etc
-    i.description(m.content);
-
-    items.push(i.build().unwrap());
-  }
+  let mut reply_items: Vec<Item> = replies
+    .iter()
+    .map(|r| {
+      let reply_url = format!(
+        "https://{}/post/{}/comment/{}",
+        Settings::get().hostname,
+        r.post_id,
+        r.id
+      );
+      build_item(&r.creator_name, &r.published, &reply_url, &r.content)
+    })
+    .collect();
+
+  let mut mention_items: Vec<Item> = mentions
+    .iter()
+    .map(|m| {
+      let mention_url = format!(
+        "https://{}/post/{}/comment/{}",
+        Settings::get().hostname,
+        m.post_id,
+        m.id
+      );
+      build_item(&m.creator_name, &m.published, &mention_url, &m.content)
+    })
+    .collect();
+
+  reply_items.append(&mut mention_items);
+  reply_items
+}
 
-  items
+fn build_item(creator_name: &str, published: &NaiveDateTime, url: &str, content: &str) -> Item {
+  let mut i = ItemBuilder::default();
+  i.title(format!("Reply from {}", creator_name));
+  let author_url = format!("https://{}/u/{}", Settings::get().hostname, creator_name);
+  i.author(format!(
+    "/u/{} <a href=\"{}\">(link)</a>",
+    creator_name, author_url
+  ));
+  let dt = DateTime::<Utc>::from_utc(*published, Utc);
+  i.pub_date(dt.to_rfc2822());
+  i.comments(url.to_owned());
+  let guid = GuidBuilder::default().permalink(true).value(url).build();
+  i.guid(guid.unwrap());
+  i.link(url.to_owned());
+  // TODO add images
+  let html = Markdown_to_HTML_rs::replace_all(&content.to_string());
+  i.description(html);
+  i.build().unwrap()
 }
 
 fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
@@ -359,9 +337,8 @@ fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
       i.link(url);
     }
 
-    // TODO find a markdown to html parser here, do images, etc
-    let mut description = format!("
-    submitted by <a href=\"{}\">{}</a> to <a href=\"{}\">{}</a><br>{} points | <a href=\"{}\">{} comments</a>",
+    // 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_name,
     community_url,
@@ -371,7 +348,8 @@ fn create_post_items(posts: Vec<PostView>) -> Vec<Item> {
     p.number_of_comments);
 
     if let Some(body) = p.body {
-      description.push_str(&format!("<br><br>{}", body));
+      let html = Markdown_to_HTML_rs::replace_all(&body);
+      description.push_str(&format!("<br><br>{}", html));
     }
 
     i.description(description);