Move import_post to fetcher::helpers module

This commit is contained in:
silverpill 2022-05-02 17:31:31 +00:00
parent 914fae8137
commit 75ef8bba7c
4 changed files with 106 additions and 101 deletions

View file

@ -1,10 +1,16 @@
use std::collections::HashMap;
use std::path::Path; use std::path::Path;
use tokio_postgres::GenericClient; use tokio_postgres::GenericClient;
use crate::activitypub::activity::Object;
use crate::activitypub::actor::ActorAddress; use crate::activitypub::actor::ActorAddress;
use crate::config::Instance; use crate::activitypub::inbox::create_note::handle_note;
use crate::activitypub::receiver::parse_object_id;
use crate::config::{Config, Instance};
use crate::errors::{DatabaseError, HttpError, ValidationError}; use crate::errors::{DatabaseError, HttpError, ValidationError};
use crate::models::posts::queries::get_post_by_object_id;
use crate::models::posts::types::Post;
use crate::models::profiles::queries::{ use crate::models::profiles::queries::{
get_profile_by_actor_id, get_profile_by_actor_id,
get_profile_by_acct, get_profile_by_acct,
@ -12,6 +18,7 @@ use crate::models::profiles::queries::{
}; };
use crate::models::profiles::types::DbActorProfile; use crate::models::profiles::types::DbActorProfile;
use super::fetchers::{ use super::fetchers::{
fetch_object,
fetch_profile, fetch_profile,
fetch_profile_by_actor_id, fetch_profile_by_actor_id,
FetchError, FetchError,
@ -104,3 +111,94 @@ pub async fn import_profile_by_actor_address(
let profile = create_profile(db_client, profile_data).await?; let profile = create_profile(db_client, profile_data).await?;
Ok(profile) Ok(profile)
} }
pub async fn import_post(
config: &Config,
db_client: &mut impl GenericClient,
object_id: String,
object_received: Option<Object>,
) -> Result<Post, ImportError> {
let instance = config.instance();
let media_dir = config.media_dir();
let mut maybe_object_id_to_fetch = Some(object_id);
let mut maybe_object = object_received;
let mut objects = vec![];
let mut redirects: HashMap<String, String> = HashMap::new();
let mut posts = vec![];
// Fetch ancestors by going through inReplyTo references
// TODO: fetch replies too
#[allow(clippy::while_let_loop)]
loop {
let object_id = match maybe_object_id_to_fetch {
Some(object_id) => {
if parse_object_id(&instance.url(), &object_id).is_ok() {
// Object is a local post
assert!(objects.len() > 0);
break;
}
match get_post_by_object_id(db_client, &object_id).await {
Ok(post) => {
// Object already fetched
if objects.len() == 0 {
// Return post corresponding to initial object ID
return Ok(post);
};
break;
},
Err(DatabaseError::NotFound(_)) => (),
Err(other_error) => return Err(other_error.into()),
};
object_id
},
None => {
// No object to fetch
break;
},
};
let object = match maybe_object {
Some(object) => object,
None => {
let object = fetch_object(&instance, &object_id).await
.map_err(|err| {
log::warn!("{}", err);
ValidationError("failed to fetch object")
})?;
log::info!("fetched object {}", object.id);
object
},
};
if object.id != object_id {
// ID of fetched object doesn't match requested ID
// Add IDs to the map of redirects
redirects.insert(object_id, object.id.clone());
maybe_object_id_to_fetch = Some(object.id.clone());
// Don't re-fetch object on the next iteration
maybe_object = Some(object);
} else {
maybe_object_id_to_fetch = object.in_reply_to.clone();
maybe_object = None;
objects.push(object);
};
}
let initial_object_id = objects[0].id.clone();
// Objects are ordered according to their place in reply tree,
// starting with the root
objects.reverse();
for object in objects {
let post = handle_note(
db_client,
&instance,
&media_dir,
object,
&redirects,
).await?;
posts.push(post);
}
let initial_post = posts.into_iter()
.find(|post| post.object_id.as_ref() == Some(&initial_object_id))
.unwrap();
Ok(initial_post)
}

View file

@ -5,6 +5,6 @@ pub mod constants;
pub mod deliverer; pub mod deliverer;
pub mod fetcher; pub mod fetcher;
mod inbox; mod inbox;
pub mod receiver; mod receiver;
pub mod views; pub mod views;
mod vocabulary; mod vocabulary;

View file

@ -1,5 +1,3 @@
use std::collections::HashMap;
use actix_web::HttpRequest; use actix_web::HttpRequest;
use regex::Regex; use regex::Regex;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
@ -15,7 +13,7 @@ use crate::models::posts::queries::{
get_post_by_object_id, get_post_by_object_id,
delete_post, delete_post,
}; };
use crate::models::posts::types::{Post, PostCreateData}; use crate::models::posts::types::PostCreateData;
use crate::models::profiles::queries::{ use crate::models::profiles::queries::{
get_profile_by_actor_id, get_profile_by_actor_id,
get_profile_by_acct, get_profile_by_acct,
@ -39,12 +37,10 @@ use super::activity::{
create_activity_accept_follow, create_activity_accept_follow,
}; };
use super::deliverer::deliver_activity; use super::deliverer::deliver_activity;
use super::fetcher::fetchers::fetch_object;
use super::fetcher::helpers::{ use super::fetcher::helpers::{
get_or_import_profile_by_actor_id, get_or_import_profile_by_actor_id,
ImportError, import_post,
}; };
use super::inbox::create_note::handle_note;
use super::inbox::update_person::handle_update_person; use super::inbox::update_person::handle_update_person;
use super::vocabulary::*; use super::vocabulary::*;
@ -145,97 +141,6 @@ fn get_object_id(object: Value) -> Result<String, ValidationError> {
Ok(object_id) Ok(object_id)
} }
pub async fn import_post(
config: &Config,
db_client: &mut impl GenericClient,
object_id: String,
object_received: Option<Object>,
) -> Result<Post, ImportError> {
let instance = config.instance();
let media_dir = config.media_dir();
let mut maybe_object_id_to_fetch = Some(object_id);
let mut maybe_object = object_received;
let mut objects = vec![];
let mut redirects: HashMap<String, String> = HashMap::new();
let mut posts = vec![];
// Fetch ancestors by going through inReplyTo references
// TODO: fetch replies too
#[allow(clippy::while_let_loop)]
loop {
let object_id = match maybe_object_id_to_fetch {
Some(object_id) => {
if parse_object_id(&instance.url(), &object_id).is_ok() {
// Object is a local post
assert!(objects.len() > 0);
break;
}
match get_post_by_object_id(db_client, &object_id).await {
Ok(post) => {
// Object already fetched
if objects.len() == 0 {
// Return post corresponding to initial object ID
return Ok(post);
};
break;
},
Err(DatabaseError::NotFound(_)) => (),
Err(other_error) => return Err(other_error.into()),
};
object_id
},
None => {
// No object to fetch
break;
},
};
let object = match maybe_object {
Some(object) => object,
None => {
let object = fetch_object(&instance, &object_id).await
.map_err(|err| {
log::warn!("{}", err);
ValidationError("failed to fetch object")
})?;
log::info!("fetched object {}", object.id);
object
},
};
if object.id != object_id {
// ID of fetched object doesn't match requested ID
// Add IDs to the map of redirects
redirects.insert(object_id, object.id.clone());
maybe_object_id_to_fetch = Some(object.id.clone());
// Don't re-fetch object on the next iteration
maybe_object = Some(object);
} else {
maybe_object_id_to_fetch = object.in_reply_to.clone();
maybe_object = None;
objects.push(object);
};
}
let initial_object_id = objects[0].id.clone();
// Objects are ordered according to their place in reply tree,
// starting with the root
objects.reverse();
for object in objects {
let post = handle_note(
db_client,
&instance,
&media_dir,
object,
&redirects,
).await?;
posts.push(post);
}
let initial_post = posts.into_iter()
.find(|post| post.object_id.as_ref() == Some(&initial_object_id))
.unwrap();
Ok(initial_post)
}
fn require_actor_signature(actor_id: &str, signer_id: &str) fn require_actor_signature(actor_id: &str, signer_id: &str)
-> Result<(), HttpError> -> Result<(), HttpError>
{ {

View file

@ -3,8 +3,10 @@ use tokio_postgres::GenericClient;
use url::Url; use url::Url;
use crate::activitypub::actor::ActorAddress; use crate::activitypub::actor::ActorAddress;
use crate::activitypub::receiver::import_post; use crate::activitypub::fetcher::helpers::{
use crate::activitypub::fetcher::helpers::import_profile_by_actor_address; import_post,
import_profile_by_actor_address,
};
use crate::config::Config; use crate::config::Config;
use crate::errors::{ValidationError, HttpError}; use crate::errors::{ValidationError, HttpError};
use crate::mastodon_api::accounts::types::Account; use crate::mastodon_api::accounts::types::Account;