From 8253aa79bd6efd120c1f2d3c2872deda9609ff3a Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Sun, 3 May 2020 06:05:58 +0900 Subject: [PATCH 1/9] Percent-encode URI segments in ap_url --- plume-models/src/blogs.rs | 8 +++++++- plume-models/src/posts.rs | 6 ++++-- plume-models/src/users.rs | 14 ++++++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/plume-models/src/blogs.rs b/plume-models/src/blogs.rs index cbef35c68..d1c1f4acc 100644 --- a/plume-models/src/blogs.rs +++ b/plume-models/src/blogs.rs @@ -20,6 +20,7 @@ use plume_common::activity_pub::{ inbox::{AsActor, FromId}, sign, ActivityStream, ApSignature, Id, IntoId, PublicKey, Source, }; +use rocket::http::uri::Uri; use serde_json; use url::Url; use webfinger::*; @@ -481,13 +482,18 @@ impl NewBlog { instance_id: i32, ) -> Result { let (pub_key, priv_key) = sign::gen_keypair(); + let instance = Instance::get_local()?; + let encoded_actor_id = Uri::percent_encode(&actor_id); Ok(NewBlog { - actor_id, + actor_id: actor_id.clone(), title, summary, instance_id, public_key: String::from_utf8(pub_key).or(Err(Error::Signature))?, private_key: Some(String::from_utf8(priv_key).or(Err(Error::Signature))?), + outbox_url: instance.compute_box(BLOG_PREFIX, &encoded_actor_id, "outbox"), + inbox_url: instance.compute_box(BLOG_PREFIX, &encoded_actor_id, "inbox"), + ap_url: instance.compute_box(BLOG_PREFIX, &encoded_actor_id, ""), ..NewBlog::default() }) } diff --git a/plume-models/src/posts.rs b/plume-models/src/posts.rs index 73c0c9155..3ff50ff53 100644 --- a/plume-models/src/posts.rs +++ b/plume-models/src/posts.rs @@ -19,6 +19,7 @@ use plume_common::{ }, utils::md_to_html, }; +use rocket::http::uri::Uri; use serde_json; use std::collections::HashSet; @@ -69,11 +70,12 @@ impl Post { .execute(conn)?; let mut post = Self::last(conn)?; if post.ap_url.is_empty() { + // Should use uri!(plume::routes::posts::detauls) if possible post.ap_url = ap_url(&format!( "{}/~/{}/{}/", CONFIG.base_url, - post.get_blog(conn)?.fqn, - post.slug + Uri::percent_encode(&post.get_blog(conn)?.fqn), + Uri::percent_encode(&post.slug) )); let _: Post = post.save_changes(conn)?; } diff --git a/plume-models/src/users.rs b/plume-models/src/users.rs index 7da04d4a3..7fc08d253 100644 --- a/plume-models/src/users.rs +++ b/plume-models/src/users.rs @@ -34,6 +34,7 @@ use reqwest::{ ClientBuilder, }; use rocket::{ + http::uri::Uri, outcome::IntoOutcome, request::{self, FromRequest, Request}, }; @@ -992,6 +993,7 @@ impl NewUser { return Err(Error::Blocklisted(x.notify_user, x.notification_text)); } + let encoded_username = Uri::percent_encode(&username); let res = User::insert( conn, NewUser { @@ -1005,11 +1007,15 @@ impl NewUser { instance_id: instance.id, public_key: String::from_utf8(pub_key).or(Err(Error::Signature))?, private_key: Some(String::from_utf8(priv_key).or(Err(Error::Signature))?), - outbox_url: instance.compute_box(USER_PREFIX, &username, "outbox"), - inbox_url: instance.compute_box(USER_PREFIX, &username, "inbox"), - ap_url: instance.compute_box(USER_PREFIX, &username, ""), + outbox_url: instance.compute_box(USER_PREFIX, &encoded_username, "outbox"), + inbox_url: instance.compute_box(USER_PREFIX, &encoded_username, "inbox"), + ap_url: instance.compute_box(USER_PREFIX, &encoded_username, ""), shared_inbox_url: Some(ap_url(&format!("{}/inbox", &instance.public_domain))), - followers_endpoint: instance.compute_box(USER_PREFIX, &username, "followers"), + followers_endpoint: instance.compute_box( + USER_PREFIX, + &encoded_username, + "followers", + ), fqn: username, avatar_id: None, }, From fd788a79b7624f062df0168dc1ce491ce18597fb Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Sun, 3 May 2020 06:07:19 +0900 Subject: [PATCH 2/9] Fix invalid Atoms --- src/routes/blogs.rs | 25 +++++++++++++++++++------ src/routes/mod.rs | 4 ++-- src/routes/user.rs | 25 +++++++++++++++++++------ 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index bba2b4023..9e043040d 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -1,5 +1,6 @@ use activitypub::collection::{OrderedCollection, OrderedCollectionPage}; -use atom_syndication::{Entry, FeedBuilder}; +use atom_syndication::{Entry, FeedBuilder, LinkBuilder}; +use chrono::{offset::TimeZone, Utc}; use diesel::SaveChangesDsl; use rocket::{ http::ContentType, @@ -361,18 +362,30 @@ pub fn outbox_page( pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> { let blog = Blog::find_by_fqn(&rockets, &name).ok()?; let conn = &*rockets.conn; + let entries = Post::get_recents_for_blog(&*conn, &blog, 15).ok()?; + let updated = if entries.is_empty() { + Utc::now() + } else { + Utc.from_utc_datetime(&entries[0].creation_date) + } + .to_rfc3339(); + let uri = uri!(atom_feed: name = name).to_string(); let feed = FeedBuilder::default() .title(blog.title.clone()) - .id(Instance::get_local() - .ok()? - .compute_box("~", &name, "atom.xml")) + .id(&uri) + .updated(updated) .entries( - Post::get_recents_for_blog(&*conn, &blog, 15) - .ok()? + entries .into_iter() .map(|p| super::post_to_atom(p, &*conn)) .collect::>(), ) + .links(vec![LinkBuilder::default() + .href(&uri) + .rel("self") + .mime_type("application/atom+xml".to_string()) + .build() + .expect("Atom feed: link error")]) .build() .ok()?; Some(Content( diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 88da993d1..640076026 100644 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -121,7 +121,6 @@ pub fn post_to_atom(post: Post, conn: &Connection) -> Entry { .content( ContentBuilder::default() .value(format!("", *post.content.get())) - .src(post.ap_url.clone()) .content_type("html".to_string()) .build() .expect("Atom feed: content error"), @@ -142,7 +141,8 @@ pub fn post_to_atom(post: Post, conn: &Connection) -> Entry { // Using RFC 4287 format, see https://tools.ietf.org/html/rfc4287#section-3.3 for dates // eg: 2003-12-13T18:30:02Z (Z is here because there is no timezone support with the NaiveDateTime crate) .published(post.creation_date.format("%Y-%m-%dT%H:%M:%SZ").to_string()) - .id(post.id.to_string()) + .updated(post.creation_date.format("%Y-%m-%dT%H:%M:%SZ").to_string()) + .id(post.ap_url.clone()) .links(vec![LinkBuilder::default() .href(post.ap_url) .build() diff --git a/src/routes/user.rs b/src/routes/user.rs index 2a952d1de..92a56da3e 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -2,7 +2,8 @@ use activitypub::{ activity::Create, collection::{OrderedCollection, OrderedCollectionPage}, }; -use atom_syndication::{Entry, FeedBuilder}; +use atom_syndication::{Entry, FeedBuilder, LinkBuilder}; +use chrono::{offset::TimeZone, Utc}; use diesel::SaveChangesDsl; use rocket::{ http::{ContentType, Cookies}, @@ -619,18 +620,30 @@ pub fn ap_followers( pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> { let conn = &*rockets.conn; let author = User::find_by_fqn(&rockets, &name).ok()?; + let entries = Post::get_recents_for_author(conn, &author, 15).ok()?; + let updated = if entries.is_empty() { + Utc::now() + } else { + Utc.from_utc_datetime(&entries[0].creation_date) + } + .to_rfc3339(); + let uri = uri!(atom_feed: name = name).to_string(); let feed = FeedBuilder::default() .title(author.display_name.clone()) - .id(Instance::get_local() - .unwrap() - .compute_box("@", &name, "atom.xml")) + .id(&uri) + .updated(updated) .entries( - Post::get_recents_for_author(conn, &author, 15) - .ok()? + entries .into_iter() .map(|p| super::post_to_atom(p, conn)) .collect::>(), ) + .links(vec![LinkBuilder::default() + .href(&uri) + .rel("self") + .mime_type("application/atom+xml".to_string()) + .build() + .expect("Atom feed: link error")]) .build() .expect("user::atom_feed: Error building Atom feed"); Some(Content( From 1c474f4c2f5b642cd16dc0e6663beea19525dde2 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Sun, 3 May 2020 06:14:21 +0900 Subject: [PATCH 3/9] Remove redundant clone according to cargo clippy --- src/routes/blogs.rs | 2 +- src/routes/mod.rs | 0 src/routes/user.rs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/routes/mod.rs diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index 9e043040d..474bdd5f0 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -371,7 +371,7 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> .to_rfc3339(); let uri = uri!(atom_feed: name = name).to_string(); let feed = FeedBuilder::default() - .title(blog.title.clone()) + .title(blog.title) .id(&uri) .updated(updated) .entries( diff --git a/src/routes/mod.rs b/src/routes/mod.rs old mode 100644 new mode 100755 diff --git a/src/routes/user.rs b/src/routes/user.rs index 92a56da3e..0fcc4251f 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -629,7 +629,7 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> .to_rfc3339(); let uri = uri!(atom_feed: name = name).to_string(); let feed = FeedBuilder::default() - .title(author.display_name.clone()) + .title(author.display_name) .id(&uri) .updated(updated) .entries( From 3a6013c5f92bd05092c2be491f724734d9516d67 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Mon, 4 May 2020 00:16:41 +0900 Subject: [PATCH 4/9] Revert "Percent-encode URI segments in ap_url" This reverts commit 8253aa79bd6efd120c1f2d3c2872deda9609ff3a. ActivityPub(JSON-LD) accepts URI. See https://github.com/Plume-org/Plume/pull/764#issuecomment-623105734 --- plume-models/src/blogs.rs | 8 +------- plume-models/src/posts.rs | 6 ++---- plume-models/src/users.rs | 14 ++++---------- 3 files changed, 7 insertions(+), 21 deletions(-) diff --git a/plume-models/src/blogs.rs b/plume-models/src/blogs.rs index d1c1f4acc..cbef35c68 100644 --- a/plume-models/src/blogs.rs +++ b/plume-models/src/blogs.rs @@ -20,7 +20,6 @@ use plume_common::activity_pub::{ inbox::{AsActor, FromId}, sign, ActivityStream, ApSignature, Id, IntoId, PublicKey, Source, }; -use rocket::http::uri::Uri; use serde_json; use url::Url; use webfinger::*; @@ -482,18 +481,13 @@ impl NewBlog { instance_id: i32, ) -> Result { let (pub_key, priv_key) = sign::gen_keypair(); - let instance = Instance::get_local()?; - let encoded_actor_id = Uri::percent_encode(&actor_id); Ok(NewBlog { - actor_id: actor_id.clone(), + actor_id, title, summary, instance_id, public_key: String::from_utf8(pub_key).or(Err(Error::Signature))?, private_key: Some(String::from_utf8(priv_key).or(Err(Error::Signature))?), - outbox_url: instance.compute_box(BLOG_PREFIX, &encoded_actor_id, "outbox"), - inbox_url: instance.compute_box(BLOG_PREFIX, &encoded_actor_id, "inbox"), - ap_url: instance.compute_box(BLOG_PREFIX, &encoded_actor_id, ""), ..NewBlog::default() }) } diff --git a/plume-models/src/posts.rs b/plume-models/src/posts.rs index 3ff50ff53..73c0c9155 100644 --- a/plume-models/src/posts.rs +++ b/plume-models/src/posts.rs @@ -19,7 +19,6 @@ use plume_common::{ }, utils::md_to_html, }; -use rocket::http::uri::Uri; use serde_json; use std::collections::HashSet; @@ -70,12 +69,11 @@ impl Post { .execute(conn)?; let mut post = Self::last(conn)?; if post.ap_url.is_empty() { - // Should use uri!(plume::routes::posts::detauls) if possible post.ap_url = ap_url(&format!( "{}/~/{}/{}/", CONFIG.base_url, - Uri::percent_encode(&post.get_blog(conn)?.fqn), - Uri::percent_encode(&post.slug) + post.get_blog(conn)?.fqn, + post.slug )); let _: Post = post.save_changes(conn)?; } diff --git a/plume-models/src/users.rs b/plume-models/src/users.rs index 7fc08d253..7da04d4a3 100644 --- a/plume-models/src/users.rs +++ b/plume-models/src/users.rs @@ -34,7 +34,6 @@ use reqwest::{ ClientBuilder, }; use rocket::{ - http::uri::Uri, outcome::IntoOutcome, request::{self, FromRequest, Request}, }; @@ -993,7 +992,6 @@ impl NewUser { return Err(Error::Blocklisted(x.notify_user, x.notification_text)); } - let encoded_username = Uri::percent_encode(&username); let res = User::insert( conn, NewUser { @@ -1007,15 +1005,11 @@ impl NewUser { instance_id: instance.id, public_key: String::from_utf8(pub_key).or(Err(Error::Signature))?, private_key: Some(String::from_utf8(priv_key).or(Err(Error::Signature))?), - outbox_url: instance.compute_box(USER_PREFIX, &encoded_username, "outbox"), - inbox_url: instance.compute_box(USER_PREFIX, &encoded_username, "inbox"), - ap_url: instance.compute_box(USER_PREFIX, &encoded_username, ""), + outbox_url: instance.compute_box(USER_PREFIX, &username, "outbox"), + inbox_url: instance.compute_box(USER_PREFIX, &username, "inbox"), + ap_url: instance.compute_box(USER_PREFIX, &username, ""), shared_inbox_url: Some(ap_url(&format!("{}/inbox", &instance.public_domain))), - followers_endpoint: instance.compute_box( - USER_PREFIX, - &encoded_username, - "followers", - ), + followers_endpoint: instance.compute_box(USER_PREFIX, &username, "followers"), fqn: username, avatar_id: None, }, From 148d0a18da1d10a8c39182ad0ff38c68998b0837 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Mon, 4 May 2020 00:43:37 +0900 Subject: [PATCH 5/9] Use absolute IRI for IDs in Atom --- src/routes/blogs.rs | 4 +++- src/routes/user.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index 474bdd5f0..23a9ab3ab 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -369,7 +369,9 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> Utc.from_utc_datetime(&entries[0].creation_date) } .to_rfc3339(); - let uri = uri!(atom_feed: name = name).to_string(); + let uri = Instance::get_local() + .ok()? + .compute_box("~", &name, "atom.xml"); let feed = FeedBuilder::default() .title(blog.title) .id(&uri) diff --git a/src/routes/user.rs b/src/routes/user.rs index 0fcc4251f..c91d5f714 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -627,7 +627,9 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> Utc.from_utc_datetime(&entries[0].creation_date) } .to_rfc3339(); - let uri = uri!(atom_feed: name = name).to_string(); + let uri = Instance::get_local() + .ok()? + .compute_box("@", &name, "atom.xml"); let feed = FeedBuilder::default() .title(author.display_name) .id(&uri) From d7ced891870c80b7257e0c62400bae86785a48b6 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Mon, 4 May 2020 00:55:19 +0900 Subject: [PATCH 6/9] Reuse formatted string --- src/routes/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/routes/mod.rs b/src/routes/mod.rs index 640076026..cb8d5bd87 100755 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -116,6 +116,7 @@ pub struct RemoteForm { } pub fn post_to_atom(post: Post, conn: &Connection) -> Entry { + let formatted_creation_date = post.creation_date.format("%Y-%m-%dT%H:%M:%SZ").to_string(); EntryBuilder::default() .title(format!("", post.title)) .content( @@ -140,8 +141,8 @@ pub fn post_to_atom(post: Post, conn: &Connection) -> Entry { ) // Using RFC 4287 format, see https://tools.ietf.org/html/rfc4287#section-3.3 for dates // eg: 2003-12-13T18:30:02Z (Z is here because there is no timezone support with the NaiveDateTime crate) - .published(post.creation_date.format("%Y-%m-%dT%H:%M:%SZ").to_string()) - .updated(post.creation_date.format("%Y-%m-%dT%H:%M:%SZ").to_string()) + .published(formatted_creation_date.clone()) + .updated(formatted_creation_date) .id(post.ap_url.clone()) .links(vec![LinkBuilder::default() .href(post.ap_url) From 6159074adf5abc31254495c42bc7f8bceceeace5 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Mon, 4 May 2020 01:52:47 +0900 Subject: [PATCH 7/9] Use parent element's creation date for Atom updated if there's no post --- src/routes/blogs.rs | 2 +- src/routes/user.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index 23a9ab3ab..9578eee47 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -364,7 +364,7 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> let conn = &*rockets.conn; let entries = Post::get_recents_for_blog(&*conn, &blog, 15).ok()?; let updated = if entries.is_empty() { - Utc::now() + Utc.from_utc_datetime(&blog.creation_date) } else { Utc.from_utc_datetime(&entries[0].creation_date) } diff --git a/src/routes/user.rs b/src/routes/user.rs index c91d5f714..77cfa437c 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -622,7 +622,7 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> let author = User::find_by_fqn(&rockets, &name).ok()?; let entries = Post::get_recents_for_author(conn, &author, 15).ok()?; let updated = if entries.is_empty() { - Utc::now() + Utc.from_utc_datetime(&author.creation_date) } else { Utc.from_utc_datetime(&entries[0].creation_date) } From ed0a41b00906dc93bede7b30fd7b00b794f71d79 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Mon, 4 May 2020 10:30:14 +0900 Subject: [PATCH 8/9] Remove uncecessary UTC conversion --- src/routes/blogs.rs | 10 ++++------ src/routes/user.rs | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index 9578eee47..0ebba5072 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -1,6 +1,5 @@ use activitypub::collection::{OrderedCollection, OrderedCollectionPage}; use atom_syndication::{Entry, FeedBuilder, LinkBuilder}; -use chrono::{offset::TimeZone, Utc}; use diesel::SaveChangesDsl; use rocket::{ http::ContentType, @@ -364,18 +363,17 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> let conn = &*rockets.conn; let entries = Post::get_recents_for_blog(&*conn, &blog, 15).ok()?; let updated = if entries.is_empty() { - Utc.from_utc_datetime(&blog.creation_date) + &blog.creation_date } else { - Utc.from_utc_datetime(&entries[0].creation_date) - } - .to_rfc3339(); + &entries[0].creation_date + }; let uri = Instance::get_local() .ok()? .compute_box("~", &name, "atom.xml"); let feed = FeedBuilder::default() .title(blog.title) .id(&uri) - .updated(updated) + .updated(updated.format("%Y-%m-%d %H:%M:%SZ").to_string()) .entries( entries .into_iter() diff --git a/src/routes/user.rs b/src/routes/user.rs index 77cfa437c..116711f9d 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -3,7 +3,6 @@ use activitypub::{ collection::{OrderedCollection, OrderedCollectionPage}, }; use atom_syndication::{Entry, FeedBuilder, LinkBuilder}; -use chrono::{offset::TimeZone, Utc}; use diesel::SaveChangesDsl; use rocket::{ http::{ContentType, Cookies}, @@ -622,18 +621,17 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> let author = User::find_by_fqn(&rockets, &name).ok()?; let entries = Post::get_recents_for_author(conn, &author, 15).ok()?; let updated = if entries.is_empty() { - Utc.from_utc_datetime(&author.creation_date) + &author.creation_date } else { - Utc.from_utc_datetime(&entries[0].creation_date) - } - .to_rfc3339(); + &entries[0].creation_date + }; let uri = Instance::get_local() .ok()? .compute_box("@", &name, "atom.xml"); let feed = FeedBuilder::default() .title(author.display_name) .id(&uri) - .updated(updated) + .updated(updated.format("%Y-%m-%d %H:%M:%SZ").to_string()) .entries( entries .into_iter() From 4f3267ed53044bc12828885ef32d2049af81cb68 Mon Sep 17 00:00:00 2001 From: Kitaiti Makoto Date: Mon, 4 May 2020 12:54:39 +0900 Subject: [PATCH 9/9] Extract routes::build_atom_feed function --- src/routes/blogs.rs | 27 +++------------------------ src/routes/mod.rs | 40 ++++++++++++++++++++++++++++++++++++++-- src/routes/user.rs | 27 +++------------------------ 3 files changed, 44 insertions(+), 50 deletions(-) diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index 0ebba5072..0c08c5360 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -1,5 +1,4 @@ use activitypub::collection::{OrderedCollection, OrderedCollectionPage}; -use atom_syndication::{Entry, FeedBuilder, LinkBuilder}; use diesel::SaveChangesDsl; use rocket::{ http::ContentType, @@ -362,32 +361,12 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> let blog = Blog::find_by_fqn(&rockets, &name).ok()?; let conn = &*rockets.conn; let entries = Post::get_recents_for_blog(&*conn, &blog, 15).ok()?; - let updated = if entries.is_empty() { - &blog.creation_date - } else { - &entries[0].creation_date - }; let uri = Instance::get_local() .ok()? .compute_box("~", &name, "atom.xml"); - let feed = FeedBuilder::default() - .title(blog.title) - .id(&uri) - .updated(updated.format("%Y-%m-%d %H:%M:%SZ").to_string()) - .entries( - entries - .into_iter() - .map(|p| super::post_to_atom(p, &*conn)) - .collect::>(), - ) - .links(vec![LinkBuilder::default() - .href(&uri) - .rel("self") - .mime_type("application/atom+xml".to_string()) - .build() - .expect("Atom feed: link error")]) - .build() - .ok()?; + let title = &blog.title; + let default_updated = &blog.creation_date; + let feed = super::build_atom_feed(entries, &uri, title, default_updated, conn); Some(Content( ContentType::new("application", "atom+xml"), feed.to_string(), diff --git a/src/routes/mod.rs b/src/routes/mod.rs index cb8d5bd87..8f4e928c9 100755 --- a/src/routes/mod.rs +++ b/src/routes/mod.rs @@ -1,6 +1,9 @@ #![warn(clippy::too_many_arguments)] use crate::template_utils::Ructe; -use atom_syndication::{ContentBuilder, Entry, EntryBuilder, LinkBuilder, Person, PersonBuilder}; +use atom_syndication::{ + ContentBuilder, Entry, EntryBuilder, Feed, FeedBuilder, LinkBuilder, Person, PersonBuilder, +}; +use chrono::naive::NaiveDateTime; use plume_models::{posts::Post, Connection, CONFIG, ITEMS_PER_PAGE}; use rocket::{ http::{ @@ -115,7 +118,40 @@ pub struct RemoteForm { pub remote: String, } -pub fn post_to_atom(post: Post, conn: &Connection) -> Entry { +pub fn build_atom_feed( + entries: Vec, + uri: &str, + title: &str, + default_updated: &NaiveDateTime, + conn: &Connection, +) -> Feed { + let updated = if entries.is_empty() { + default_updated + } else { + &entries[0].creation_date + }; + + FeedBuilder::default() + .title(title) + .id(uri) + .updated(updated.format("%Y-%m-%d %H:%M:%SZ").to_string()) + .entries( + entries + .into_iter() + .map(|p| post_to_atom(p, conn)) + .collect::>(), + ) + .links(vec![LinkBuilder::default() + .href(uri) + .rel("self") + .mime_type("application/atom+xml".to_string()) + .build() + .expect("Atom feed: link error")]) + .build() + .expect("user::atom_feed: Error building Atom feed") +} + +fn post_to_atom(post: Post, conn: &Connection) -> Entry { let formatted_creation_date = post.creation_date.format("%Y-%m-%dT%H:%M:%SZ").to_string(); EntryBuilder::default() .title(format!("", post.title)) diff --git a/src/routes/user.rs b/src/routes/user.rs index 116711f9d..e0bfd7832 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -2,7 +2,6 @@ use activitypub::{ activity::Create, collection::{OrderedCollection, OrderedCollectionPage}, }; -use atom_syndication::{Entry, FeedBuilder, LinkBuilder}; use diesel::SaveChangesDsl; use rocket::{ http::{ContentType, Cookies}, @@ -620,32 +619,12 @@ pub fn atom_feed(name: String, rockets: PlumeRocket) -> Option> let conn = &*rockets.conn; let author = User::find_by_fqn(&rockets, &name).ok()?; let entries = Post::get_recents_for_author(conn, &author, 15).ok()?; - let updated = if entries.is_empty() { - &author.creation_date - } else { - &entries[0].creation_date - }; let uri = Instance::get_local() .ok()? .compute_box("@", &name, "atom.xml"); - let feed = FeedBuilder::default() - .title(author.display_name) - .id(&uri) - .updated(updated.format("%Y-%m-%d %H:%M:%SZ").to_string()) - .entries( - entries - .into_iter() - .map(|p| super::post_to_atom(p, conn)) - .collect::>(), - ) - .links(vec![LinkBuilder::default() - .href(&uri) - .rel("self") - .mime_type("application/atom+xml".to_string()) - .build() - .expect("Atom feed: link error")]) - .build() - .expect("user::atom_feed: Error building Atom feed"); + let title = &author.display_name; + let default_updated = &author.creation_date; + let feed = super::build_atom_feed(entries, &uri, title, default_updated, conn); Some(Content( ContentType::new("application", "atom+xml"), feed.to_string(),