diff --git a/plume-models/src/posts.rs b/plume-models/src/posts.rs index d96d96b7..16014e62 100644 --- a/plume-models/src/posts.rs +++ b/plume-models/src/posts.rs @@ -222,49 +222,52 @@ 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() - .fold((None, vec![]), |(blog, mut authors), link| { - let url: String = link.into(); - match User::from_url(conn, url.clone()) { - Some(user) => { - authors.push(user); - (blog, authors) - }, - None => (blog.or_else(|| Blog::from_url(conn, url)), authors) - } + if let Some(post) = Post::find_by_ap_url(conn, article.object_props.id_string().unwrap_or(String::new())) { + post + } else { + let (blog, authors) = article.object_props.attributed_to_link_vec::() + .expect("Post::from_activity: attributedTo error") + .into_iter() + .fold((None, vec![]), |(blog, mut authors), link| { + let url: String = link.into(); + match User::from_url(conn, url.clone()) { + Some(user) => { + authors.push(user); + (blog, authors) + }, + None => (blog.or_else(|| Blog::from_url(conn, url)), authors) + } + }); + + let title = article.object_props.name_string().expect("Post::from_activity: title error"); + let post = Post::insert(conn, NewPost { + blog_id: blog.expect("Received a new Article without a blog").id, + slug: title.to_kebab_case(), + title: title, + content: SafeString::new(&article.object_props.content_string().expect("Post::from_activity: content error")), + published: true, + license: String::from("CC-0"), // TODO + // FIXME: This is wrong: with this logic, we may use the display URL as the AP ID. We need two different fields + ap_url: article.object_props.url_string().unwrap_or(article.object_props.id_string().expect("Post::from_activity: url + id error")) }); - let title = article.object_props.name_string().expect("Post::from_activity: title error"); - let post = Post::insert(conn, NewPost { - blog_id: blog.expect("Received a new Article without a blog").id, - slug: title.to_kebab_case(), - title: title, - content: SafeString::new(&article.object_props.content_string().expect("Post::from_activity: content error")), - published: true, - license: String::from("CC-0"), // TODO - // FIXME: This is wrong: with this logic, we may use the display URL as the AP ID. We need two different fields - ap_url: article.object_props.url_string().unwrap_or(article.object_props.id_string().expect("Post::from_activity: url + id error")) - }); - - for author in authors.into_iter() { - PostAuthor::insert(conn, NewPostAuthor { - post_id: post.id, - author_id: author.id - }); - } - - // save mentions - if let Some(serde_json::Value::Array(tags)) = article.object_props.tag.clone() { - for tag in tags.into_iter() { - serde_json::from_value::(tag) - .map(|m| Mention::from_activity(conn, m, post.id, true)) - .ok(); + for author in authors.into_iter() { + PostAuthor::insert(conn, NewPostAuthor { + post_id: post.id, + author_id: author.id + }); } + + // save mentions + if let Some(serde_json::Value::Array(tags)) = article.object_props.tag.clone() { + for tag in tags.into_iter() { + serde_json::from_value::(tag) + .map(|m| Mention::from_activity(conn, m, post.id, true)) + .ok(); + } + } + post } - post } } diff --git a/plume-models/src/users.rs b/plume-models/src/users.rs index d13c29d7..63a8b26b 100644 --- a/plume-models/src/users.rs +++ b/plume-models/src/users.rs @@ -159,11 +159,14 @@ impl User { .send(); match req { Ok(mut res) => { - let text = &res.text().unwrap(); - let ap_sign: ApSignature = serde_json::from_str(text).unwrap(); - let mut json: CustomPerson = serde_json::from_str(text).unwrap(); - json.custom_props = ap_sign; // without this workaround, publicKey is not correctly deserialized - Some(User::from_activity(conn, json, Url::parse(url.as_ref()).unwrap().host_str().unwrap().to_string())) + if let Ok(text) = &res.text() { + if let Ok(ap_sign) = serde_json::from_str::(text) { + if let Ok(mut json) = serde_json::from_str::(text) { + json.custom_props = ap_sign; // without this workaround, publicKey is not correctly deserialized + Some(User::from_activity(conn, json, Url::parse(url.as_ref()).unwrap().host_str().unwrap().to_string())) + } else { None } + } else { None } + } else { None } }, Err(e) => { println!("User fetch error: {:?}", e); diff --git a/src/routes/user.rs b/src/routes/user.rs index c1b0d7ed..e72b6725 100644 --- a/src/routes/user.rs +++ b/src/routes/user.rs @@ -47,18 +47,20 @@ fn details<'r>(name: String, conn: DbConn, account: Option, worker: State< 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"); + if !user.get_instance(&*conn).local { + 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) } - Err(e) => println!("Error while fetching articles in background: {:?}", e) } - } - })); + })); + } Template::render("users/details", json!({ "user": user.to_json(&*conn),