Skip to content

Commit d58baeb

Browse files
authored
Add fallback to trigger create on update failure (#2328)
1 parent ecec5a1 commit d58baeb

File tree

4 files changed

+76
-12
lines changed

4 files changed

+76
-12
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: minor
2+
Type: added
3+
4+
Added fallback to trigger create handling when updates fail for missing posts or comments, ensuring objects are properly created.

includes/collection/class-posts.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ public static function get_by_guid( $guid ) {
8484

8585
if ( ! $post_id ) {
8686
return new \WP_Error(
87-
'activitypub_object_not_found',
88-
\__( 'Object not found', 'activitypub' ),
87+
'activitypub_post_not_found',
88+
\__( 'Post not found', 'activitypub' ),
8989
array( 'status' => 404 )
9090
);
9191
}

includes/handler/class-update.php

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,17 @@ class Update {
2222
* Initialize the class, registering WordPress hooks.
2323
*/
2424
public static function init() {
25-
\add_action( 'activitypub_inbox_update', array( self::class, 'handle_update' ), 10, 2 );
25+
\add_action( 'activitypub_inbox_update', array( self::class, 'handle_update' ), 10, 3 );
2626
}
2727

2828
/**
2929
* Handle "Update" requests.
3030
*
31-
* @param array $activity The Activity object.
32-
* @param int $user_id The user ID. Always null for Update activities.
31+
* @param array $activity The Activity object.
32+
* @param int $user_id The user ID. Always null for Update activities.
33+
* @param \Activitypub\Activity\Activity $activity_object The activity object. Default null.
3334
*/
34-
public static function handle_update( $activity, $user_id ) {
35+
public static function handle_update( $activity, $user_id, $activity_object ) {
3536
$object_type = $activity['object']['type'] ?? '';
3637

3738
switch ( $object_type ) {
@@ -60,7 +61,7 @@ public static function handle_update( $activity, $user_id ) {
6061
case 'Video':
6162
case 'Event':
6263
case 'Document':
63-
self::update_object( $activity, $user_id );
64+
self::update_object( $activity, $user_id, $activity_object );
6465
break;
6566

6667
/*
@@ -76,21 +77,42 @@ public static function handle_update( $activity, $user_id ) {
7677
/**
7778
* Update an Object.
7879
*
79-
* @param array $activity The Activity object.
80-
* @param int $user_id The user ID. Always null for Update activities.
80+
* @param array $activity The Activity object.
81+
* @param int $user_id The user ID. Always null for Update activities.
82+
* @param \Activitypub\Activity\Activity $activity_object The activity object. Default null.
8183
*/
82-
public static function update_object( $activity, $user_id ) {
83-
$result = new \WP_Error( 'activitypub_update_failed', 'Update failed' );
84+
public static function update_object( $activity, $user_id, $activity_object ) {
85+
$result = new \WP_Error( 'activitypub_update_failed', 'Update failed' );
86+
$updated = true;
8487

8588
// Check for private and/or direct messages.
8689
if ( is_activity_reply( $activity ) ) {
8790
$comment_data = Interactions::update_comment( $activity );
8891

89-
if ( ! empty( $comment_data['comment_ID'] ) ) {
92+
if ( false === $comment_data ) {
93+
$updated = false;
94+
} elseif ( ! empty( $comment_data['comment_ID'] ) ) {
9095
$result = \get_comment( $comment_data['comment_ID'] );
9196
}
9297
} else {
9398
$result = Posts::update( $activity );
99+
100+
if ( \is_wp_error( $result ) && 'activitypub_post_not_found' === $result->get_error_code() ) {
101+
$updated = false;
102+
}
103+
}
104+
105+
// There is no object to update, try to trigger create instead.
106+
if ( ! $updated ) {
107+
/**
108+
* Fires when a Create activity is received for an existing object.
109+
*
110+
* @param array $activity The activity-object.
111+
* @param int $user_id The id of the local blog-user.
112+
* @param \Activitypub\Activity\Activity $activity_object The activity object.
113+
*/
114+
\do_action( 'activitypub_inbox_create', $activity, $user_id, $activity_object );
115+
return false;
94116
}
95117

96118
$success = ( $result && ! \is_wp_error( $result ) );

tests/phpunit/tests/includes/handler/class-test-update.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,44 @@
1919
*/
2020
class Test_Update extends \WP_UnitTestCase {
2121

22+
/**
23+
* Test that the activitypub_inbox_create fallback is triggered.
24+
*/
25+
public function test_activitypub_inbox_create_fallback() {
26+
$called = false;
27+
$test_actor = 'https://example.com/users/fallback';
28+
$activity = array(
29+
'id' => 'https://example.com/activities/12345',
30+
'type' => 'Create',
31+
'actor' => $test_actor,
32+
'object' => array(
33+
'id' => 'https://example.com/objects/12345',
34+
'type' => 'Note',
35+
'content' => 'Test note',
36+
),
37+
);
38+
39+
// Add a fallback handler for the action.
40+
\add_action(
41+
'activitypub_inbox_create',
42+
function ( $activity_data ) use ( &$called, $test_actor ) {
43+
if ( isset( $activity_data['actor'] ) && $activity_data['actor'] === $test_actor ) {
44+
$called = true;
45+
}
46+
},
47+
10,
48+
3
49+
);
50+
51+
// Call the handler (simulate inbox create for unknown type).
52+
\do_action( 'activitypub_inbox_update', $activity, $this->user_id, null );
53+
54+
$this->assertTrue( $called, 'The fallback activitypub_inbox_create action should be triggered.' );
55+
56+
// Clean up by removing the action.
57+
\remove_all_actions( 'activitypub_inbox_create' );
58+
}
59+
2260
/**
2361
* User ID.
2462
*

0 commit comments

Comments
 (0)