Handle non-nested Undo(Follow) activities
This commit is contained in:
parent
f2037c9516
commit
1b588a86e0
2 changed files with 55 additions and 13 deletions
|
@ -4,7 +4,7 @@ use tokio_postgres::GenericClient;
|
||||||
|
|
||||||
use crate::activitypub::{
|
use crate::activitypub::{
|
||||||
identifiers::parse_local_actor_id,
|
identifiers::parse_local_actor_id,
|
||||||
receiver::find_object_id,
|
receiver::{deserialize_into_object_id, find_object_id},
|
||||||
vocabulary::{ANNOUNCE, FOLLOW, LIKE},
|
vocabulary::{ANNOUNCE, FOLLOW, LIKE},
|
||||||
};
|
};
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
|
@ -23,12 +23,15 @@ use crate::models::{
|
||||||
delete_reaction,
|
delete_reaction,
|
||||||
get_reaction_by_remote_activity_id,
|
get_reaction_by_remote_activity_id,
|
||||||
},
|
},
|
||||||
relationships::queries::unfollow,
|
relationships::queries::{
|
||||||
|
get_follow_request_by_activity_id,
|
||||||
|
unfollow,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use super::HandlerResult;
|
use super::HandlerResult;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Undo {
|
struct UndoFollow {
|
||||||
actor: String,
|
actor: String,
|
||||||
object: Value,
|
object: Value,
|
||||||
}
|
}
|
||||||
|
@ -36,8 +39,10 @@ struct Undo {
|
||||||
async fn handle_undo_follow(
|
async fn handle_undo_follow(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
db_client: &mut impl GenericClient,
|
db_client: &mut impl GenericClient,
|
||||||
activity: Undo,
|
activity: Value,
|
||||||
) -> HandlerResult {
|
) -> HandlerResult {
|
||||||
|
let activity: UndoFollow = serde_json::from_value(activity)
|
||||||
|
.map_err(|_| ValidationError("unexpected activity structure"))?;
|
||||||
let source_profile = get_profile_by_remote_actor_id(
|
let source_profile = get_profile_by_remote_actor_id(
|
||||||
db_client,
|
db_client,
|
||||||
&activity.actor,
|
&activity.actor,
|
||||||
|
@ -58,25 +63,45 @@ async fn handle_undo_follow(
|
||||||
Ok(Some(FOLLOW))
|
Ok(Some(FOLLOW))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Undo {
|
||||||
|
actor: String,
|
||||||
|
#[serde(deserialize_with = "deserialize_into_object_id")]
|
||||||
|
object: String,
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn handle_undo(
|
pub async fn handle_undo(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
db_client: &mut impl GenericClient,
|
db_client: &mut impl GenericClient,
|
||||||
activity: Value,
|
activity: Value,
|
||||||
) -> HandlerResult {
|
) -> HandlerResult {
|
||||||
let activity: Undo = serde_json::from_value(activity)
|
if let Some(FOLLOW) = activity["object"]["type"].as_str() {
|
||||||
.map_err(|_| ValidationError("unexpected activity structure"))?;
|
// Undo() with nested follow activity
|
||||||
if let Some(FOLLOW) = activity.object["type"].as_str() {
|
return handle_undo_follow(config, db_client, activity).await;
|
||||||
// Object type is currently required for processing Undo(Follow)
|
|
||||||
// because activity IDs of remote follow requests are not stored.
|
|
||||||
return handle_undo_follow(config, db_client, activity).await
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let activity: Undo = serde_json::from_value(activity)
|
||||||
|
.map_err(|_| ValidationError("unexpected activity structure"))?;
|
||||||
let actor_profile = get_profile_by_remote_actor_id(
|
let actor_profile = get_profile_by_remote_actor_id(
|
||||||
db_client,
|
db_client,
|
||||||
&activity.actor,
|
&activity.actor,
|
||||||
).await?;
|
).await?;
|
||||||
let object_id = find_object_id(&activity.object)?;
|
|
||||||
match get_reaction_by_remote_activity_id(db_client, &object_id).await {
|
match get_follow_request_by_activity_id(db_client, &activity.object).await {
|
||||||
|
Ok(follow_request) => {
|
||||||
|
// Undo(Follow)
|
||||||
|
unfollow(
|
||||||
|
db_client,
|
||||||
|
&follow_request.source_id,
|
||||||
|
&follow_request.target_id,
|
||||||
|
).await?;
|
||||||
|
return Ok(Some(FOLLOW));
|
||||||
|
},
|
||||||
|
Err(DatabaseError::NotFound(_)) => (), // try other object types
|
||||||
|
Err(other_error) => return Err(other_error.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
match get_reaction_by_remote_activity_id(db_client, &activity.object).await {
|
||||||
Ok(reaction) => {
|
Ok(reaction) => {
|
||||||
// Undo(Like)
|
// Undo(Like)
|
||||||
if reaction.author_id != actor_profile.id {
|
if reaction.author_id != actor_profile.id {
|
||||||
|
@ -93,7 +118,7 @@ pub async fn handle_undo(
|
||||||
// Undo(Announce)
|
// Undo(Announce)
|
||||||
let post = match get_post_by_remote_object_id(
|
let post = match get_post_by_remote_object_id(
|
||||||
db_client,
|
db_client,
|
||||||
&object_id,
|
&activity.object,
|
||||||
).await {
|
).await {
|
||||||
Ok(post) => post,
|
Ok(post) => post,
|
||||||
// Ignore undo if neither reaction nor repost is found
|
// Ignore undo if neither reaction nor repost is found
|
||||||
|
|
|
@ -272,6 +272,23 @@ pub async fn get_follow_request_by_id(
|
||||||
Ok(request)
|
Ok(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_follow_request_by_activity_id(
|
||||||
|
db_client: &impl GenericClient,
|
||||||
|
activity_id: &str,
|
||||||
|
) -> Result<DbFollowRequest, DatabaseError> {
|
||||||
|
let maybe_row = db_client.query_opt(
|
||||||
|
"
|
||||||
|
SELECT follow_request
|
||||||
|
FROM follow_request
|
||||||
|
WHERE activity_id = $1
|
||||||
|
",
|
||||||
|
&[&activity_id],
|
||||||
|
).await?;
|
||||||
|
let row = maybe_row.ok_or(DatabaseError::NotFound("follow request"))?;
|
||||||
|
let request = row.try_get("follow_request")?;
|
||||||
|
Ok(request)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_followers(
|
pub async fn get_followers(
|
||||||
db_client: &impl GenericClient,
|
db_client: &impl GenericClient,
|
||||||
profile_id: &Uuid,
|
profile_id: &Uuid,
|
||||||
|
|
Loading…
Reference in a new issue