Improve the background article fetching code

This commit is contained in:
Bat 2018-07-26 22:59:41 +02:00
parent bd259891f3
commit 0314629d99
3 changed files with 62 additions and 54 deletions

View File

@ -222,49 +222,52 @@ impl Post {
impl FromActivity<Article, PgConnection> for Post { impl FromActivity<Article, PgConnection> for Post {
fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post { fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post {
println!("Article: {:?}", article); if let Some(post) = Post::find_by_ap_url(conn, article.object_props.id_string().unwrap_or(String::new())) {
let (blog, authors) = article.object_props.attributed_to_link_vec::<Id>() post
.expect("Post::from_activity: attributedTo error") } else {
.into_iter() let (blog, authors) = article.object_props.attributed_to_link_vec::<Id>()
.fold((None, vec![]), |(blog, mut authors), link| { .expect("Post::from_activity: attributedTo error")
let url: String = link.into(); .into_iter()
match User::from_url(conn, url.clone()) { .fold((None, vec![]), |(blog, mut authors), link| {
Some(user) => { let url: String = link.into();
authors.push(user); match User::from_url(conn, url.clone()) {
(blog, authors) Some(user) => {
}, authors.push(user);
None => (blog.or_else(|| Blog::from_url(conn, url)), authors) (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"); for author in authors.into_iter() {
let post = Post::insert(conn, NewPost { PostAuthor::insert(conn, NewPostAuthor {
blog_id: blog.expect("Received a new Article without a blog").id, post_id: post.id,
slug: title.to_kebab_case(), author_id: author.id
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::<link::Mention>(tag)
.map(|m| Mention::from_activity(conn, m, post.id, true))
.ok();
} }
// 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::<link::Mention>(tag)
.map(|m| Mention::from_activity(conn, m, post.id, true))
.ok();
}
}
post
} }
post
} }
} }

View File

@ -159,11 +159,14 @@ impl User {
.send(); .send();
match req { match req {
Ok(mut res) => { Ok(mut res) => {
let text = &res.text().unwrap(); if let Ok(text) = &res.text() {
let ap_sign: ApSignature = serde_json::from_str(text).unwrap(); if let Ok(ap_sign) = serde_json::from_str::<ApSignature>(text) {
let mut json: CustomPerson = serde_json::from_str(text).unwrap(); if let Ok(mut json) = serde_json::from_str::<CustomPerson>(text) {
json.custom_props = ap_sign; // without this workaround, publicKey is not correctly deserialized 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())) 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) => { Err(e) => {
println!("User fetch error: {:?}", e); println!("User fetch error: {:?}", e);

View File

@ -47,18 +47,20 @@ fn details<'r>(name: String, conn: DbConn, account: Option<User>, worker: State<
let n_followers = user.get_followers(&*conn).len(); let n_followers = user.get_followers(&*conn).len();
// Fetch new articles // Fetch new articles
let user_clone = user.clone(); if !user.get_instance(&*conn).local {
worker.execute(Thunk::of(move || { let user_clone = user.clone();
for create_act in user_clone.fetch_outbox::<Create>() { worker.execute(Thunk::of(move || {
match create_act.create_props.object_object::<Article>() { for create_act in user_clone.fetch_outbox::<Create>() {
Ok(article) => { match create_act.create_props.object_object::<Article>() {
Post::from_activity(&*other_conn, article, user_clone.clone().into_id()); Ok(article) => {
println!("Fetched article from remote user"); 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!({ Template::render("users/details", json!({
"user": user.to_json(&*conn), "user": user.to_json(&*conn),