2022-12-09 23:03:07 +00:00
|
|
|
use serde::Deserialize;
|
2022-12-09 21:16:53 +00:00
|
|
|
use serde_json::Value;
|
2022-05-30 22:23:06 +00:00
|
|
|
|
2023-02-18 23:52:48 +00:00
|
|
|
use mitra_config::Config;
|
2023-03-30 20:27:17 +00:00
|
|
|
use mitra_models::{
|
|
|
|
database::{DatabaseClient, DatabaseError},
|
2023-04-24 15:35:32 +00:00
|
|
|
posts::queries::{create_post, get_post_by_remote_object_id},
|
2023-03-30 20:27:17 +00:00
|
|
|
posts::types::PostCreateData,
|
|
|
|
};
|
2023-02-18 23:52:48 +00:00
|
|
|
|
2023-04-24 15:35:32 +00:00
|
|
|
use super::HandlerResult;
|
2022-05-30 22:23:06 +00:00
|
|
|
use crate::activitypub::{
|
|
|
|
fetcher::helpers::{get_or_import_profile_by_actor_id, import_post},
|
2022-07-16 01:49:27 +00:00
|
|
|
identifiers::parse_local_object_id,
|
2022-12-09 23:03:07 +00:00
|
|
|
receiver::deserialize_into_object_id,
|
2023-02-05 20:46:58 +00:00
|
|
|
vocabulary::{CREATE, DELETE, DISLIKE, LIKE, NOTE, UNDO, UPDATE},
|
2022-05-30 22:23:06 +00:00
|
|
|
};
|
2022-12-09 21:16:53 +00:00
|
|
|
use crate::errors::ValidationError;
|
2023-03-25 21:50:10 +00:00
|
|
|
use crate::media::MediaStorage;
|
2022-05-30 22:23:06 +00:00
|
|
|
|
2022-12-09 23:03:07 +00:00
|
|
|
#[derive(Deserialize)]
|
|
|
|
struct Announce {
|
|
|
|
id: String,
|
|
|
|
actor: String,
|
|
|
|
#[serde(deserialize_with = "deserialize_into_object_id")]
|
|
|
|
object: String,
|
|
|
|
}
|
|
|
|
|
2022-05-30 22:23:06 +00:00
|
|
|
pub async fn handle_announce(
|
|
|
|
config: &Config,
|
2023-01-17 23:14:18 +00:00
|
|
|
db_client: &mut impl DatabaseClient,
|
2022-12-09 21:16:53 +00:00
|
|
|
activity: Value,
|
2022-05-30 22:23:06 +00:00
|
|
|
) -> HandlerResult {
|
2023-02-05 20:46:58 +00:00
|
|
|
if let Some(CREATE | DELETE | DISLIKE | LIKE | UNDO | UPDATE) =
|
2022-12-14 16:34:30 +00:00
|
|
|
activity["object"]["type"].as_str()
|
|
|
|
{
|
2022-12-09 23:03:07 +00:00
|
|
|
// Ignore wrapped activities from Lemmy
|
|
|
|
// https://codeberg.org/fediverse/fep/src/branch/main/feps/fep-1b12.md
|
|
|
|
return Ok(None);
|
|
|
|
};
|
|
|
|
let activity: Announce = serde_json::from_value(activity)
|
2022-12-09 21:16:53 +00:00
|
|
|
.map_err(|_| ValidationError("unexpected activity structure"))?;
|
2022-05-30 22:23:06 +00:00
|
|
|
let repost_object_id = activity.id;
|
2023-04-24 15:35:32 +00:00
|
|
|
match get_post_by_remote_object_id(db_client, &repost_object_id).await {
|
2022-05-30 22:23:06 +00:00
|
|
|
Ok(_) => return Ok(None), // Ignore if repost already exists
|
|
|
|
Err(DatabaseError::NotFound(_)) => (),
|
|
|
|
Err(other_error) => return Err(other_error.into()),
|
|
|
|
};
|
2023-03-26 00:52:09 +00:00
|
|
|
let instance = config.instance();
|
|
|
|
let storage = MediaStorage::from(config);
|
2023-04-24 15:35:32 +00:00
|
|
|
let author =
|
|
|
|
get_or_import_profile_by_actor_id(db_client, &instance, &storage, &activity.actor).await?;
|
|
|
|
let post_id = match parse_local_object_id(&instance.url(), &activity.object) {
|
2022-05-30 22:23:06 +00:00
|
|
|
Ok(post_id) => post_id,
|
|
|
|
Err(_) => {
|
|
|
|
// Try to get remote post
|
2023-04-24 15:35:32 +00:00
|
|
|
let post = import_post(db_client, &instance, &storage, activity.object, None).await?;
|
2022-05-30 22:23:06 +00:00
|
|
|
post.id
|
2023-04-24 15:35:32 +00:00
|
|
|
}
|
2022-05-30 22:23:06 +00:00
|
|
|
};
|
2023-04-24 15:35:32 +00:00
|
|
|
let repost_data = PostCreateData::repost(post_id, Some(repost_object_id.clone()));
|
2022-12-13 19:28:06 +00:00
|
|
|
match create_post(db_client, &author.id, repost_data).await {
|
|
|
|
Ok(_) => Ok(Some(NOTE)),
|
|
|
|
Err(DatabaseError::AlreadyExists("post")) => {
|
|
|
|
// Ignore activity if repost already exists (with a different
|
|
|
|
// object ID, or due to race condition in a handler).
|
2022-12-21 19:20:28 +00:00
|
|
|
log::warn!("repost already exists: {}", repost_object_id);
|
2022-12-13 19:28:06 +00:00
|
|
|
Ok(None)
|
2023-04-24 15:35:32 +00:00
|
|
|
}
|
2023-01-29 19:57:17 +00:00
|
|
|
// May return "post not found" error if post if not public
|
2022-12-13 19:28:06 +00:00
|
|
|
Err(other_error) => Err(other_error.into()),
|
|
|
|
}
|
2022-05-30 22:23:06 +00:00
|
|
|
}
|
2022-12-09 23:03:07 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2023-04-24 15:35:32 +00:00
|
|
|
use serde_json::json;
|
2022-12-09 23:03:07 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deserialize_announce() {
|
|
|
|
let activity_raw = json!({
|
|
|
|
"type": "Announce",
|
|
|
|
"id": "https://example.com/activities/321",
|
|
|
|
"actor": "https://example.com/users/1",
|
|
|
|
"object": "https://test.org/objects/999",
|
|
|
|
});
|
|
|
|
let activity: Announce = serde_json::from_value(activity_raw).unwrap();
|
|
|
|
assert_eq!(activity.object, "https://test.org/objects/999");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_deserialize_announce_nested() {
|
|
|
|
let activity_raw = json!({
|
|
|
|
"type": "Announce",
|
|
|
|
"id": "https://example.com/activities/321",
|
|
|
|
"actor": "https://example.com/users/1",
|
|
|
|
"object": {
|
|
|
|
"type": "Note",
|
|
|
|
"id": "https://test.org/objects/999",
|
|
|
|
},
|
|
|
|
});
|
|
|
|
let activity: Announce = serde_json::from_value(activity_raw).unwrap();
|
|
|
|
assert_eq!(activity.object, "https://test.org/objects/999");
|
|
|
|
}
|
|
|
|
}
|