Process follower migration request in background

This commit is contained in:
silverpill 2023-02-26 19:03:48 +00:00
parent 62069dc011
commit e02ebebe02
2 changed files with 85 additions and 55 deletions

View file

@ -3,6 +3,10 @@ use uuid::Uuid;
use mitra_config::Config; use mitra_config::Config;
use crate::activitypub::{ use crate::activitypub::{
builders::{
move_person::prepare_move_person,
undo_follow::prepare_undo_follow,
},
fetcher::helpers::get_or_import_profile_by_actor_address, fetcher::helpers::get_or_import_profile_by_actor_address,
HandlerError, HandlerError,
}; };
@ -15,9 +19,15 @@ use crate::database::{
use crate::errors::ValidationError; use crate::errors::ValidationError;
use crate::mastodon_api::accounts::helpers::follow_or_create_request; use crate::mastodon_api::accounts::helpers::follow_or_create_request;
use crate::models::{ use crate::models::{
profiles::types::DbActorProfile,
posts::mentions::mention_to_address, posts::mentions::mention_to_address,
relationships::queries::{get_followers, get_following}, profiles::queries::get_profile_by_acct,
profiles::types::DbActorProfile,
relationships::queries::{
follow,
get_followers,
get_following,
unfollow,
},
users::types::User, users::types::User,
}; };
use crate::webfinger::types::ActorAddress; use crate::webfinger::types::ActorAddress;
@ -108,6 +118,64 @@ pub async fn import_follows_task(
Ok(()) Ok(())
} }
pub async fn move_followers_task(
config: &Config,
db_pool: &DbPool,
current_user: User,
from_actor_id: &str,
maybe_from_profile: Option<DbActorProfile>,
address_list: Vec<ActorAddress>,
) -> Result<(), anyhow::Error> {
let db_client = &mut **get_database_client(db_pool).await?;
let instance = config.instance();
let mut followers = vec![];
for follower_address in address_list {
let follower_acct = follower_address.acct(&instance.hostname());
// TODO: fetch unknown profiles
let follower = get_profile_by_acct(db_client, &follower_acct).await?;
if let Some(remote_actor) = follower.actor_json {
// Add remote actor to activity recipients list
followers.push(remote_actor);
} else {
// Immediately move local followers (only if alias can be verified)
if let Some(ref from_profile) = maybe_from_profile {
match unfollow(db_client, &follower.id, &from_profile.id).await {
Ok(maybe_follow_request_id) => {
// Send Undo(Follow) to a remote actor
let remote_actor = from_profile.actor_json.as_ref()
.expect("actor data must be present");
let follow_request_id = maybe_follow_request_id
.expect("follow request must exist");
prepare_undo_follow(
&instance,
&current_user,
remote_actor,
&follow_request_id,
).enqueue(db_client).await?;
},
// Not a follower, ignore
Err(DatabaseError::NotFound(_)) => continue,
Err(other_error) => return Err(other_error.into()),
};
match follow(db_client, &follower.id, &current_user.id).await {
Ok(_) => (),
// Ignore if already following
Err(DatabaseError::AlreadyExists(_)) => (),
Err(other_error) => return Err(other_error.into()),
};
};
};
};
prepare_move_person(
&instance,
&current_user,
from_actor_id,
followers,
None,
).enqueue(db_client).await?;
Ok(())
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::activitypub::actors::types::Actor; use crate::activitypub::actors::types::Actor;

View file

@ -11,12 +11,6 @@ use actix_web_httpauth::extractors::bearer::BearerAuth;
use mitra_config::Config; use mitra_config::Config;
use mitra_utils::passwords::hash_password; use mitra_utils::passwords::hash_password;
use crate::activitypub::{
builders::{
move_person::prepare_move_person,
undo_follow::prepare_undo_follow,
},
};
use crate::database::{get_database_client, DatabaseError, DbPool}; use crate::database::{get_database_client, DatabaseError, DbPool};
use crate::errors::ValidationError; use crate::errors::ValidationError;
use crate::http::get_request_base_url; use crate::http::get_request_base_url;
@ -27,14 +21,14 @@ use crate::mastodon_api::{
}; };
use crate::models::{ use crate::models::{
profiles::helpers::find_aliases, profiles::helpers::find_aliases,
profiles::queries::{get_profile_by_acct, get_profile_by_remote_actor_id}, profiles::queries::get_profile_by_remote_actor_id,
relationships::queries::{follow, unfollow},
users::queries::set_user_password, users::queries::set_user_password,
}; };
use super::helpers::{ use super::helpers::{
export_followers, export_followers,
export_follows, export_follows,
import_follows_task, import_follows_task,
move_followers_task,
parse_address_list, parse_address_list,
}; };
use super::types::{ use super::types::{
@ -158,52 +152,20 @@ async fn move_followers(
return Err(ValidationError("old profile is not an alias").into()); return Err(ValidationError("old profile is not an alias").into());
}; };
}; };
let mut followers = vec![];
let address_list = parse_address_list(&request_data.followers_csv)?; let address_list = parse_address_list(&request_data.followers_csv)?;
for follower_address in address_list { let current_user_clone = current_user.clone();
let follower_acct = follower_address.acct(&instance.hostname()); tokio::spawn(async move {
// TODO: fetch unknown profiles move_followers_task(
let follower = get_profile_by_acct(db_client, &follower_acct).await?; &config,
if let Some(remote_actor) = follower.actor_json { &db_pool,
// Add remote actor to activity recipients list current_user_clone,
followers.push(remote_actor); &request_data.from_actor_id,
} else { maybe_from_profile,
// Immediately move local followers (only if alias can be verified) address_list,
if let Some(ref from_profile) = maybe_from_profile { ).await.unwrap_or_else(|error| {
match unfollow(db_client, &follower.id, &from_profile.id).await { log::error!("move followers: {}", error);
Ok(maybe_follow_request_id) => { });
// Send Undo(Follow) to a remote actor });
let remote_actor = from_profile.actor_json.as_ref()
.expect("actor data must be present");
let follow_request_id = maybe_follow_request_id
.expect("follow request must exist");
prepare_undo_follow(
&instance,
&current_user,
remote_actor,
&follow_request_id,
).enqueue(db_client).await?;
},
// Not a follower, ignore
Err(DatabaseError::NotFound(_)) => continue,
Err(other_error) => return Err(other_error.into()),
};
match follow(db_client, &follower.id, &current_user.id).await {
Ok(_) => (),
// Ignore if already following
Err(DatabaseError::AlreadyExists(_)) => (),
Err(other_error) => return Err(other_error.into()),
};
};
};
};
prepare_move_person(
&instance,
&current_user,
&request_data.from_actor_id,
followers,
None,
).enqueue(db_client).await?;
let account = Account::from_user( let account = Account::from_user(
&get_request_base_url(connection_info), &get_request_base_url(connection_info),