Handle Like, Undo/Like activities from Mastodon, add tests (fixes #2378) (#2380)

This commit is contained in:
Nutomic 2022-07-29 15:32:12 +02:00 committed by GitHub
parent 8bfeb4b627
commit a85334c675
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 66 additions and 11 deletions

View file

@ -0,0 +1,7 @@
{
"@context":"https://www.w3.org/ns/activitystreams",
"id":"https://mastodon.madrid/users/felix#likes/212340",
"type":"Like",
"actor":"https://mastodon.madrid/users/felix",
"object":"https://ds9.lemmy.ml/post/147"
}

View file

@ -0,0 +1,12 @@
{
"@context":"https://www.w3.org/ns/activitystreams",
"id":"https://mastodon.madrid/users/felix#likes/212341/undo",
"type":"Undo",
"actor":"https://mastodon.madrid/users/felix",
"object": {
"id":"https://mastodon.madrid/users/felix#likes/212341",
"type":"Like",
"actor":"https://mastodon.madrid/users/felix",
"object":"https://ds9.lemmy.ml/post/147"
}
}

View file

@ -46,14 +46,13 @@ impl UndoVote {
.await?? .await??
.into(); .into();
let object = Vote::new(object, actor, &community, kind.clone(), context)?; let object = Vote::new(object, actor, kind.clone(), context)?;
let id = generate_activity_id( let id = generate_activity_id(
UndoType::Undo, UndoType::Undo,
&context.settings().get_protocol_and_hostname(), &context.settings().get_protocol_and_hostname(),
)?; )?;
let undo_vote = UndoVote { let undo_vote = UndoVote {
actor: ObjectId::new(actor.actor_id()), actor: ObjectId::new(actor.actor_id()),
to: vec![community.actor_id()],
object, object,
cc: vec![public()], cc: vec![public()],
kind: UndoType::Undo, kind: UndoType::Undo,

View file

@ -31,13 +31,11 @@ impl Vote {
pub(in crate::activities::voting) fn new( pub(in crate::activities::voting) fn new(
object: &PostOrComment, object: &PostOrComment,
actor: &ApubPerson, actor: &ApubPerson,
community: &ApubCommunity,
kind: VoteType, kind: VoteType,
context: &LemmyContext, context: &LemmyContext,
) -> Result<Vote, LemmyError> { ) -> Result<Vote, LemmyError> {
Ok(Vote { Ok(Vote {
actor: ObjectId::new(actor.actor_id()), actor: ObjectId::new(actor.actor_id()),
to: vec![community.actor_id()],
object: ObjectId::new(object.ap_id()), object: ObjectId::new(object.ap_id()),
cc: vec![public()], cc: vec![public()],
kind: kind.clone(), kind: kind.clone(),
@ -59,7 +57,7 @@ impl Vote {
}) })
.await?? .await??
.into(); .into();
let vote = Vote::new(object, actor, &community, kind, context)?; let vote = Vote::new(object, actor, kind, context)?;
let activity = AnnouncableActivities::Vote(vote); let activity = AnnouncableActivities::Vote(vote);
send_activity_in_community(activity, actor, &community, vec![], context).await send_activity_in_community(activity, actor, &community, vec![], context).await

View file

@ -197,3 +197,43 @@ impl ActivityHandler for GroupInboxActivities {
} }
} }
} }
#[cfg(test)]
mod tests {
use crate::{
activity_lists::{GroupInboxActivities, PersonInboxActivities, SiteInboxActivities},
protocol::tests::test_parse_lemmy_item,
};
#[test]
fn test_group_inbox() {
test_parse_lemmy_item::<GroupInboxActivities>("assets/lemmy/activities/following/follow.json")
.unwrap();
test_parse_lemmy_item::<GroupInboxActivities>(
"assets/lemmy/activities/create_or_update/create_note.json",
)
.unwrap();
}
#[test]
fn test_person_inbox() {
test_parse_lemmy_item::<PersonInboxActivities>("assets/lemmy/activities/following/accept.json")
.unwrap();
test_parse_lemmy_item::<PersonInboxActivities>(
"assets/lemmy/activities/create_or_update/create_note.json",
)
.unwrap();
test_parse_lemmy_item::<PersonInboxActivities>(
"assets/lemmy/activities/create_or_update/create_private_message.json",
)
.unwrap();
}
#[test]
fn test_site_inbox() {
test_parse_lemmy_item::<SiteInboxActivities>(
"assets/lemmy/activities/deletion/delete_user.json",
)
.unwrap();
}
}

View file

@ -56,6 +56,7 @@ where
for<'de2> <ActorT as ApubObject>::ApubType: serde::Deserialize<'de2>, for<'de2> <ActorT as ApubObject>::ApubType: serde::Deserialize<'de2>,
{ {
let activity_value: Value = serde_json::from_str(&payload)?; let activity_value: Value = serde_json::from_str(&payload)?;
debug!("Received activity {:#}", payload.as_str());
let activity: Activity = serde_json::from_value(activity_value.clone())?; let activity: Activity = serde_json::from_value(activity_value.clone())?;
// Log the activity, so we avoid receiving and parsing it twice. // Log the activity, so we avoid receiving and parsing it twice.
let insert = insert_activity(activity.id(), activity_value, false, true, context.pool()).await?; let insert = insert_activity(activity.id(), activity_value, false, true, context.pool()).await?;

View file

@ -45,6 +45,8 @@ mod tests {
test_json::<Delete>("assets/mastodon/activities/delete.json").unwrap(); test_json::<Delete>("assets/mastodon/activities/delete.json").unwrap();
test_json::<FollowCommunity>("assets/mastodon/activities/follow.json").unwrap(); test_json::<FollowCommunity>("assets/mastodon/activities/follow.json").unwrap();
test_json::<UndoFollowCommunity>("assets/mastodon/activities/undo_follow.json").unwrap(); test_json::<UndoFollowCommunity>("assets/mastodon/activities/undo_follow.json").unwrap();
test_json::<Vote>("assets/mastodon/activities/like_page.json").unwrap();
test_json::<UndoVote>("assets/mastodon/activities/undo_like_page.json").unwrap();
} }
#[test] #[test]

View file

@ -11,10 +11,8 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct UndoVote { pub struct UndoVote {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "deserialize_one_or_many")]
pub(crate) to: Vec<Url>,
pub(crate) object: Vote, pub(crate) object: Vote,
#[serde(deserialize_with = "deserialize_one_or_many")] #[serde(deserialize_with = "deserialize_one_or_many", default)]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: UndoType, pub(crate) kind: UndoType,

View file

@ -14,10 +14,8 @@ use url::Url;
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Vote { pub struct Vote {
pub(crate) actor: ObjectId<ApubPerson>, pub(crate) actor: ObjectId<ApubPerson>,
#[serde(deserialize_with = "deserialize_one_or_many")]
pub(crate) to: Vec<Url>,
pub(crate) object: ObjectId<PostOrComment>, pub(crate) object: ObjectId<PostOrComment>,
#[serde(deserialize_with = "deserialize_one_or_many")] #[serde(deserialize_with = "deserialize_one_or_many", default)]
pub(crate) cc: Vec<Url>, pub(crate) cc: Vec<Url>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub(crate) kind: VoteType, pub(crate) kind: VoteType,