diff --git a/Cargo.lock b/Cargo.lock index 9b58dc73..409af0a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,6 +89,16 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "atom_syndication" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "derive_builder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-xml 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "backtrace" version = "0.3.6" @@ -332,6 +342,25 @@ dependencies = [ "syntex_fmt_macros 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "derive_builder" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "derive_builder_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "derive_builder_core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "diesel" version = "1.2.2" @@ -985,6 +1014,7 @@ name = "plume" version = "0.1.0" dependencies = [ "activitypub 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "atom_syndication 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "diesel 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1100,6 +1130,16 @@ dependencies = [ "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quick-xml" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "encoding_rs 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "0.3.15" @@ -2074,6 +2114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum antidote 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34fde25430d87a9388dadbe6e34d7f72a462c8b43ac8d309b42b0a8505d7e2a5" "checksum array_tool 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8f8cb5d814eb646a863c4f24978cff2880c4be96ad8cde2c0f0678732902e271" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum atom_syndication 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0a9a7ab83635ff7a3b04856f4ad95324dccc9b947ab1e790fc5c769ee6d6f60c" "checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" @@ -2103,6 +2144,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum csrf 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "38f2ee2a7e76740d81de006e61eff53206c56448a30d8017b4ac97b5486682bd" "checksum data-encoding 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "67df0571a74bf0d97fb8b2ed22abdd9a48475c96bd327db968b7d9cace99655e" "checksum derive-error-chain 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4450afbe280461e78299b39182a085b70e3e71be049cf4a588ad72f1e44d33" +"checksum derive_builder 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c998e6ab02a828dd9735c18f154e14100e674ed08cb4e1938f0e4177543f439" +"checksum derive_builder_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "735e24ee9e5fa8e16b86da5007856e97d592e11867e45d76e0c0d0a164a0b757" "checksum diesel 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24815a0c2094f2c8dafe74ab3b9e975892f44acbb94b4d4b4898025a7615efa4" "checksum diesel_derives 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6471a2b637b414d3ee1504cf230409a550381c79204282f8fe06c527e4ae56be" "checksum dotenv 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a70de3c590ce18df70743cace1cf12565637a0b26fd8b04ef10c7d33fdc66cdc" @@ -2186,6 +2229,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118" "checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" "checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32" +"checksum quick-xml 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b14c27e04216596a49f2b82398a24f67ed9f131a5c0e0235496ea446bdacfb12" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" diff --git a/Cargo.toml b/Cargo.toml index f76918f2..b5667050 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ name = "plume" version = "0.1.0" [dependencies] activitypub = "0.1.1" +atom_syndication = "0.6" colored = "1.6" dotenv = "*" failure = "0.1" diff --git a/plume-common/src/activity_pub/inbox.rs b/plume-common/src/activity_pub/inbox.rs index ffbdbe6e..4a302a13 100644 --- a/plume-common/src/activity_pub/inbox.rs +++ b/plume-common/src/activity_pub/inbox.rs @@ -1,4 +1,4 @@ -use activitypub::{Object, activity::{Create, Delete}}; +use activitypub::{Object, activity::Create}; use activity_pub::Id; diff --git a/plume-models/src/comments.rs b/plume-models/src/comments.rs index 39926d5c..b7511d8d 100644 --- a/plume-models/src/comments.rs +++ b/plume-models/src/comments.rs @@ -105,7 +105,7 @@ impl FromActivity for Comment { sensitive: false // "sensitive" is not a standard property, we need to think about how to support it with the activitypub crate }); - // save mentions + // save mentionsd if let Some(serde_json::Value::Array(tags)) = note.object_props.tag.clone() { for tag in tags.into_iter() { serde_json::from_value::(tag) diff --git a/src/main.rs b/src/main.rs index e93429ee..9e1083bd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ #![plugin(rocket_codegen)] extern crate activitypub; +extern crate atom_syndication; extern crate colored; extern crate diesel; extern crate dotenv; @@ -45,6 +46,7 @@ fn main() { routes::blogs::new, routes::blogs::new_auth, routes::blogs::create, + routes::blogs::atom_feed, routes::comments::create, @@ -98,6 +100,7 @@ fn main() { routes::user::ap_followers, routes::user::new, routes::user::create, + routes::user::atom_feed, routes::well_known::host_meta, routes::well_known::nodeinfo, diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index 528e0ae7..f4d783ae 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -1,7 +1,9 @@ use activitypub::collection::OrderedCollection; +use atom_syndication::{Entry, FeedBuilder}; use rocket::{ request::LenientForm, - response::{Redirect, Flash} + response::{Redirect, Flash, content::Content}, + http::ContentType }; use rocket_contrib::Template; use serde_json; @@ -129,3 +131,18 @@ fn outbox(name: String, conn: DbConn) -> ActivityStream { let blog = Blog::find_local(&*conn, name).unwrap(); blog.outbox(&*conn) } + +#[get("/~//atom.xml")] +fn atom_feed(name: String, conn: DbConn) -> Content { + let blog = Blog::find_by_fqn(&*conn, name.clone()).expect("Unable to find blog"); + let feed = FeedBuilder::default() + .title(blog.title.clone()) + .id(Instance::get_local(&*conn).unwrap().compute_box("~", name, "atom.xml")) + .entries(Post::get_recents_for_blog(&*conn, &blog, 15) + .into_iter() + .map(|p| super::post_to_atom(p, &*conn)) + .collect::>()) + .build() + .expect("Error building Atom feed"); + Content(ContentType::new("application", "atom+xml"), feed.to_string()) +} diff --git a/src/routes/mod.rs b/src/routes/mod.rs index c46fc2f2..dd2be41a 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,3 +1,5 @@ +use atom_syndication::{ContentBuilder, Entry, EntryBuilder, LinkBuilder, Person, PersonBuilder}; +use diesel::PgConnection; use rocket::{ http::uri::{FromUriParam, UriDisplay}, response::NamedFile @@ -7,6 +9,8 @@ use std::{ path::{Path, PathBuf} }; +use plume_models::posts::Post; + macro_rules! may_fail { ($account:expr, $expr:expr, $template:expr, $msg:expr, | $res:ident | $block:block) => { { @@ -75,6 +79,25 @@ impl Page { } } +pub fn post_to_atom(post: Post, conn: &PgConnection) -> Entry { + EntryBuilder::default() + .title(post.title.clone()) + .content(ContentBuilder::default() + .value(format!("", *post.content.get())) + .src(post.ap_url.clone()) + .content_type("html".to_string()) + .build().expect("Atom feed: content error")) + .authors(post.get_authors(&*conn) + .into_iter() + .map(|a| PersonBuilder::default() + .name(a.display_name) + .uri(a.ap_url) + .build().expect("Atom feed: author error")) + .collect::>()) + .links(vec![LinkBuilder::default().href(post.ap_url).build().expect("Atom feed: link error")]) + .build().expect("Atom feed: entry error") +} + pub mod blogs; pub mod comments; pub mod errors; diff --git a/src/routes/user.rs b/src/routes/user.rs index 2688b38b..2246c05f 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -3,10 +3,12 @@ use activitypub::{ collection::OrderedCollection, object::Article }; +use atom_syndication::{Entry, FeedBuilder}; use rocket::{ State, request::LenientForm, - response::{Redirect, Flash} + response::{Redirect, Flash, Content}, + http::ContentType }; use rocket_contrib::Template; use serde_json; @@ -276,3 +278,18 @@ fn ap_followers(name: String, conn: DbConn, _ap: ApRequest) -> ActivityStream/atom.xml")] +fn atom_feed(name: String, conn: DbConn) -> Content { + let author = User::find_by_fqn(&*conn, name.clone()).expect("Unable to find author"); + let feed = FeedBuilder::default() + .title(author.display_name.clone()) + .id(Instance::get_local(&*conn).unwrap().compute_box("~", name, "atom.xml")) + .entries(Post::get_recents_for_author(&*conn, &author, 15) + .into_iter() + .map(|p| super::post_to_atom(p, &*conn)) + .collect::>()) + .build() + .expect("Error building Atom feed"); + Content(ContentType::new("application", "atom+xml"), feed.to_string()) +}