Skip to content

Commit

Permalink
ActivityPub: Support update of posts and people (#421)
Browse files Browse the repository at this point in the history
  • Loading branch information
akirk authored Dec 20, 2024
1 parent 4dd64ae commit 0b11935
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 0 deletions.
29 changes: 29 additions & 0 deletions feed-parsers/class-feed-parser-activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public function __construct( Feed $friends_feed ) {
\add_action( 'activitypub_inbox_like', array( $this, 'handle_received_like' ), 15, 2 );
\add_action( 'activitypub_inbox_undo', array( $this, 'handle_received_undo' ), 15, 2 );
\add_action( 'activitypub_inbox_move', array( $this, 'handle_received_move' ), 15, 2 );
\add_action( 'activitypub_inbox_update', array( $this, 'handle_received_update' ), 15, 2 );
\add_action( 'activitypub_handled_create', array( $this, 'activitypub_handled_create' ), 10, 4 );

\add_action( 'friends_user_feed_activated', array( $this, 'queue_follow_user' ), 10 );
Expand Down Expand Up @@ -794,6 +795,10 @@ public function handle_received_move( $activity, $user_id ) {
return $this->handle_received_activity( $activity, $user_id, 'move' );
}

public function handle_received_update( $activity, $user_id ) {
return $this->handle_received_activity( $activity, $user_id, 'update' );
}

public function handle_received_delete( $activity, $user_id ) {
return $this->handle_received_activity( $activity, $user_id, 'delete' );
}
Expand Down Expand Up @@ -846,6 +851,7 @@ public function handle_received_activity( $activity, $user_id, $type ) {
'like',
'unlike',
'move',
'update',
),
true
) ) {
Expand Down Expand Up @@ -920,6 +926,11 @@ protected function process_incoming_activity( $type, $activity, $user_id, $user_
switch ( $type ) {
case 'create':
return $this->handle_incoming_create( $activity['object'] );
case 'update':
if ( isset( $activity['object']['type'] ) && 'Person' === $activity['object']['type'] ) {
return $this->handle_incoming_update_person( $activity['object'], $user_feed );
}
return $this->handle_incoming_create( $activity['object'] );
case 'delete':
return $this->handle_incoming_delete( $activity['object'] );
case 'announce':
Expand Down Expand Up @@ -1044,7 +1055,25 @@ private function handle_incoming_create( $activity ) {
return new Feed_Item( $data );
}

/**
* We received a update of a person, handle it.
*
* @param array $activity The object from ActivityPub.
* @param User_Feed $user_feed The user feed.
*/
private function handle_incoming_update_person( $activity, User_Feed $user_feed ) {
$friend_user = $user_feed->get_friend_user();
$this->log( 'Received person update for ' . $friend_user->user_login, compact( 'activity' ) );

if ( ! empty( $activity['summary'] ) ) {
$friend_user->description = $activity['summary'];
}
if ( ! empty( $activity['icon']['url'] ) ) {
$friend_user->update_user_icon_url( $activity['icon']['url'] );
}
$friend_user->save();
return null; // No feed item to submit.
}
/**
* We received a delete of a post, handle it.
*
Expand Down
150 changes: 150 additions & 0 deletions tests/test-activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,156 @@ public function test_incoming_post() {
delete_user_option( 'activitypub_friends_show_replies', $this->friend_id );
}

public function test_incoming_update_person() {
$user_feed = User_Feed::get_by_url( $this->actor );
$friend_user = $user_feed->get_friend_user();
$old_description = $friend_user->description;

$new_description = 'New Description' . wp_rand();

$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/' . get_current_user_id() . '/inbox' );
$request->set_body(
wp_json_encode(
array(
'type' => 'Update',
'id' => $this->actor . '#update',
'actor' => $this->actor,
'object' => array(
'type' => 'Person',
'id' => $this->actor,
'summary' => $new_description,
),
)
)
);
$request->set_header( 'Content-type', 'application/json' );

$response = $this->server->dispatch( $request );
$this->assertEquals( 202, $response->get_status() );

$friend_user = $user_feed->get_friend_user();

$this->assertNotEquals( $old_description, $new_description );
$this->assertEquals( $friend_user->description, $new_description );
}

public function test_incoming_update_post() {
update_user_option( 'activitypub_friends_show_replies', '1', $this->friend_id );
$now = time() - 10;
$status_id = 123;

$posts = get_posts(
array(
'post_type' => Friends::CPT,
'author' => $this->friend_id,
)
);

$post_count = count( $posts );

// Let's post a new Note through the REST API.
$date = gmdate( \DATE_W3C, $now++ );
$id = 'test' . $status_id;
$content = 'Test ' . $date . ' ' . wp_rand();
$attachment_url = 'https://mastodon.local/files/original/1234.png';
$attachment_width = 400;
$attachment_height = 600;

$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/' . get_current_user_id() . '/inbox' );
$request->set_body(
wp_json_encode(
array(
'type' => 'Create',
'id' => $id,
'actor' => $this->actor,
'object' => array(
'type' => 'Note',
'id' => $id,
'attributedTo' => $this->actor,
'inReplyTo' => null,
'content' => $content,
'url' => 'https://mastodon.local/users/akirk/statuses/' . $status_id,
'published' => $date,
'attachment' => array(
array(
'type' => 'Document',
'mediaType' => 'image/png',
'url' => $attachment_url,
'name' => '',
'blurhash' => '',
'width' => $attachment_width,
'height' => $attachment_height,

),
),
),
)
)
);
$request->set_header( 'Content-type', 'application/json' );

$response = $this->server->dispatch( $request );
$this->assertEquals( 202, $response->get_status() );

$posts = get_posts(
array(
'post_type' => Friends::CPT,
'author' => $this->friend_id,
)
);

$this->assertEquals( $post_count + 1, count( $posts ) );
$this->assertStringStartsWith( $content, $posts[0]->post_content );
$this->assertStringContainsString( '<img src="' . esc_url( $attachment_url ) . '" width="' . esc_attr( $attachment_width ) . '" height="' . esc_attr( $attachment_height ) . '"', $posts[0]->post_content );
$this->assertEquals( $this->friend_id, $posts[0]->post_author );

// Update the post
$date = gmdate( \DATE_W3C, $now++ );
$id = 'test' . $status_id;
$updated_content = 'Test ' . $date . ' ' . wp_rand();

$request = new \WP_REST_Request( 'POST', '/activitypub/1.0/users/' . get_current_user_id() . '/inbox' );
$request->set_body(
wp_json_encode(
array(
'type' => 'Update',
'id' => $id . '#update',
'actor' => 'https://mastodon.local/@akirk',

'object' =>
array(
'type' => 'Note',
'id' => $id,
'attributedTo' => 'https://mastodon.local/@akirk',
'inReplyTo' => null,
'content' => $updated_content,
'url' => 'https://mastodon.local/users/akirk/statuses/' . $status_id,
'published' => $date,
),
)
)
);

$request->set_header( 'Content-type', 'application/json' );

$response = $this->server->dispatch( $request );
$this->assertEquals( 202, $response->get_status() );

$posts = get_posts(
array(
'post_type' => Friends::CPT,
'author' => $this->friend_id,
)
);

$this->assertEquals( $post_count + 1, count( $posts ) );
$this->assertEquals( $updated_content, $posts[0]->post_content );
$this->assertEquals( $this->friend_id, $posts[0]->post_author );
$this->assertEquals( $this->friend_name, get_post_meta( $posts[0]->ID, 'author', true ) );

delete_user_option( 'activitypub_friends_show_replies', $this->friend_id );
}

public function test_incoming_mention_of_others() {
$now = time() - 10;
$status_id = 123;
Expand Down

0 comments on commit 0b11935

Please sign in to comment.