diff --git a/plume-models/src/posts.rs b/plume-models/src/posts.rs index 947f7742..d96d96b7 100644 --- a/plume-models/src/posts.rs +++ b/plume-models/src/posts.rs @@ -178,7 +178,10 @@ impl Post { let mut article = Article::default(); article.object_props.set_name_string(self.title.clone()).expect("Article::into_activity: name error"); article.object_props.set_id_string(self.ap_url.clone()).expect("Article::into_activity: id error"); - article.object_props.set_attributed_to_link_vec::(self.get_authors(conn).into_iter().map(|x| Id::new(x.ap_url)).collect()).expect("Article::into_activity: attributedTo error"); + + let mut authors = self.get_authors(conn).into_iter().map(|x| Id::new(x.ap_url)).collect::>(); + authors.push(self.get_blog(conn).into_id()); // add the blog URL here too + article.object_props.set_attributed_to_link_vec::(authors).expect("Article::into_activity: attributedTo error"); article.object_props.set_content_string(self.content.get().clone()).expect("Article::into_activity: content error"); article.object_props.set_published_utctime(Utc.from_utc_datetime(&self.creation_date)).expect("Article::into_activity: published error"); article.object_props.set_tag_link_vec(mentions).expect("Article::into_activity: tag error"); @@ -219,6 +222,7 @@ impl Post { impl FromActivity for Post { fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post { + println!("Article: {:?}", article); let (blog, authors) = article.object_props.attributed_to_link_vec::() .expect("Post::from_activity: attributedTo error") .into_iter() diff --git a/plume-models/src/users.rs b/plume-models/src/users.rs index 33a61afe..d13c29d7 100644 --- a/plume-models/src/users.rs +++ b/plume-models/src/users.rs @@ -1,5 +1,5 @@ use activitypub::{ - Actor, Object, Endpoint, CustomObject, + Activity, Actor, Object, Endpoint, CustomObject, actor::Person, collection::OrderedCollection }; @@ -251,6 +251,28 @@ impl User { ActivityStream::new(coll) } + pub fn fetch_outbox(&self) -> Vec { + let req = Client::new() + .get(&self.outbox_url[..]) + .header(Accept(ap_accept_header().into_iter().map(|h| qitem(h.parse::().expect("Invalid Content-Type"))).collect())) + .send(); + match req { + Ok(mut res) => { + let text = &res.text().unwrap(); + let json: serde_json::Value = serde_json::from_str(text).unwrap(); + json["items"].as_array() + .expect("Outbox.items is not an array") + .into_iter() + .filter_map(|j| serde_json::from_value(j.clone()).ok()) + .collect::>() + }, + Err(e) => { + println!("User outbox fetch error: {:?}", e); + vec![] + } + } + } + fn get_activities(&self, conn: &PgConnection) -> Vec { use schema::posts; use schema::post_authors; diff --git a/src/routes/user.rs b/src/routes/user.rs index cab8e6a0..c1b0d7ed 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -1,6 +1,7 @@ use activitypub::{ - activity::Follow, - collection::OrderedCollection + activity::{Create, Follow}, + collection::OrderedCollection, + object::Article }; use rocket::{ State, @@ -14,7 +15,7 @@ use workerpool::{Pool, thunk::*}; use plume_common::activity_pub::{ ActivityStream, broadcast, Id, IntoId, ApRequest, - inbox::{Notify} + inbox::{FromActivity, Notify} }; use plume_common::utils; use plume_models::{ @@ -38,13 +39,27 @@ fn me(user: Option) -> Result> { } #[get("/@/", rank = 2)] -fn details(name: String, conn: DbConn, account: Option) -> Template { +fn details<'r>(name: String, conn: DbConn, account: Option, worker: State>>, other_conn: DbConn) -> Template { may_fail!(account, User::find_by_fqn(&*conn, name), "Couldn't find requested user", |user| { let recents = Post::get_recents_for_author(&*conn, &user, 6); let reshares = Reshare::get_recents_for_author(&*conn, &user, 6); let user_id = user.id.clone(); let n_followers = user.get_followers(&*conn).len(); + // Fetch new articles + let user_clone = user.clone(); + worker.execute(Thunk::of(move || { + for create_act in user_clone.fetch_outbox::() { + match create_act.create_props.object_object::
() { + Ok(article) => { + Post::from_activity(&*other_conn, article, user_clone.clone().into_id()); + println!("Fetched article from remote user"); + } + Err(e) => println!("Error while fetching articles in background: {:?}", e) + } + } + })); + Template::render("users/details", json!({ "user": user.to_json(&*conn), "instance_url": user.get_instance(&*conn).public_domain,