diff --git a/includes/functions.php b/includes/functions.php index 90110e5f7..e7ecf1c99 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -1580,6 +1580,15 @@ function add_to_outbox( $data, $activity_type = 'Create', $user_id = 0, $content return false; } + // If the user is disabled, fall back to the blog user when available. + if ( is_user_disabled( $user_id ) ) { + if ( is_user_disabled( Actors::BLOG_USER_ID ) ) { + return false; + } else { + $user_id = Actors::BLOG_USER_ID; + } + } + set_wp_object_state( $data, 'federate' ); $outbox_activity_id = Outbox::add( $activity_object, $activity_type, $user_id, $content_visibility ); diff --git a/tests/includes/class-test-signature.php b/tests/includes/class-test-signature.php index dfcfd05ef..5d9988d73 100644 --- a/tests/includes/class-test-signature.php +++ b/tests/includes/class-test-signature.php @@ -58,7 +58,7 @@ public function test_signature_legacy() { $this->assertEquals( $key_pair['private_key'], $private_key ); // Check application user. - $user = Actors::get_by_id( -1 ); + $user = Actors::get_by_id( Actors::APPLICATION_USER_ID ); $public_key = 'public key ' . $user->get__id(); $private_key = 'private key ' . $user->get__id(); @@ -73,8 +73,9 @@ public function test_signature_legacy() { $this->assertEquals( $key_pair['private_key'], $private_key ); // Check blog user. - \define( 'ACTIVITYPUB_DISABLE_BLOG_USER', false ); - $user = Actors::get_by_id( 0 ); + \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + $user = Actors::get_by_id( Actors::BLOG_USER_ID ); + \delete_option( 'activitypub_actor_mode' ); $public_key = 'public key ' . $user->get__id(); $private_key = 'private key ' . $user->get__id(); diff --git a/tests/includes/collection/class-test-outbox.php b/tests/includes/collection/class-test-outbox.php index da46c3117..e0d9c0d2d 100644 --- a/tests/includes/collection/class-test-outbox.php +++ b/tests/includes/collection/class-test-outbox.php @@ -12,7 +12,35 @@ * * @coversDefaultClass \Activitypub\Collection\Outbox */ -class Test_Outbox extends \Activitypub\Tests\ActivityPub_TestCase_Cache_HTTP { +class Test_Outbox extends \WP_UnitTestCase { + /** + * User ID for testing. + * + * @var int + */ + protected static $user_id; + + /** + * Set up test resources. + */ + public static function set_up_before_class() { + parent::set_up_before_class(); + self::$user_id = self::factory()->user->create( array( 'role' => 'author' ) ); + + // Add activitypub capability to the user. + \get_user_by( 'id', self::$user_id )->add_cap( 'activitypub' ); + + \add_filter( 'pre_schedule_event', '__return_false' ); + } + + /** + * Clean up test resources. + */ + public static function tear_down_after_class() { + \delete_option( 'activitypub_actor_mode' ); + \wp_delete_user( self::$user_id ); + \remove_filter( 'pre_schedule_event', '__return_false' ); + } /** * Test add an item to the outbox. @@ -26,11 +54,13 @@ class Test_Outbox extends \Activitypub\Tests\ActivityPub_TestCase_Cache_HTTP { * @param string $json The JSON representation of the data. */ public function test_add( $data, $type, $user_id, $json ) { + \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); + $id = \Activitypub\add_to_outbox( $data, $type, $user_id ); $this->assertIsInt( $id ); - $post = get_post( $id ); + $post = \get_post( $id ); $this->assertInstanceOf( 'WP_Post', $post ); $this->assertEquals( 'pending', $post->post_status ); @@ -39,8 +69,11 @@ public function test_add( $data, $type, $user_id, $json ) { $activity = json_decode( $post->post_content ); $this->assertSame( $data['content'], $activity->content ); - $this->assertEquals( $type, get_post_meta( $id, '_activitypub_activity_type', true ) ); - $this->assertEquals( 'user', get_post_meta( $id, '_activitypub_activity_actor', true ) ); + $this->assertEquals( $type, \get_post_meta( $id, '_activitypub_activity_type', true ) ); + + // Fall back to blog if user does not have the activitypub capability. + $actor_type = \user_can( $user_id, 'activitypub' ) ? 'user' : 'blog'; + $this->assertEquals( $actor_type, \get_post_meta( $id, '_activitypub_activity_actor', true ) ); } /** @@ -53,13 +86,13 @@ public function activity_object_provider() { array( array( '@context' => 'https://www.w3.org/ns/activitystreams', - 'id' => 'https://example.com/1', + 'id' => 'https://example.com/' . self::$user_id, 'type' => 'Note', 'content' => '
This is a note
', ), 'Create', 1, - '{"@context":["https:\/\/www.w3.org\/ns\/activitystreams",{"Hashtag":"as:Hashtag","sensitive":"as:sensitive"}],"id":"https:\/\/example.com\/1","type":"Note","content":"\u003Cp\u003EThis is a note\u003C\/p\u003E","contentMap":{"en":"\u003Cp\u003EThis is a note\u003C\/p\u003E"},"tag":[],"to":["https:\/\/www.w3.org\/ns\/activitystreams#Public"],"cc":[],"mediaType":"text\/html","sensitive":false}', + '{"@context":["https:\/\/www.w3.org\/ns\/activitystreams",{"Hashtag":"as:Hashtag","sensitive":"as:sensitive"}],"id":"https:\/\/example.com\/' . self::$user_id . '","type":"Note","content":"\u003Cp\u003EThis is a note\u003C\/p\u003E","contentMap":{"en":"\u003Cp\u003EThis is a note\u003C\/p\u003E"},"tag":[],"to":["https:\/\/www.w3.org\/ns\/activitystreams#Public"],"cc":[],"mediaType":"text\/html","sensitive":false}', ), array( array( @@ -74,4 +107,43 @@ public function activity_object_provider() { ), ); } + + /** + * Test add an item to the outbox with a user. + * + * @covers ::add + * @dataProvider author_object_provider + * + * @param string $mode The actor mode. + * @param int $user_id The user ID. + * @param string $expected_actor The expected actor. + */ + public function test_author_fallbacks( $mode, $user_id, $expected_actor ) { + \update_option( 'activitypub_actor_mode', $mode ); + + $user_id = $user_id ?? self::$user_id; + $data = array( + '@context' => 'https://www.w3.org/ns/activitystreams', + 'id' => 'https://example.com/' . $user_id, + 'type' => 'Note', + 'content' => 'This is a note
', + ); + + $id = \Activitypub\add_to_outbox( $data, 'Create', $user_id ); + $this->assertEquals( $expected_actor, \get_post_meta( $id, '_activitypub_activity_actor', true ) ); + } + + /** + * Data provider for test_author_fallbacks. + * + * @return array[] + */ + public function author_object_provider() { + return array( + array( ACTIVITYPUB_ACTOR_AND_BLOG_MODE, self::$user_id, 'user' ), // Not sure why we can't access self::$user_id directly. + array( ACTIVITYPUB_ACTOR_AND_BLOG_MODE, 90210, 'blog' ), + array( ACTIVITYPUB_BLOG_MODE, 90210, 'blog' ), + array( ACTIVITYPUB_ACTOR_MODE, 90210, false ), + ); + } } diff --git a/tests/includes/scheduler/class-test-actor.php b/tests/includes/scheduler/class-test-actor.php index 7dd413b48..d178018da 100644 --- a/tests/includes/scheduler/class-test-actor.php +++ b/tests/includes/scheduler/class-test-actor.php @@ -88,6 +88,7 @@ public function test_user_update() { * @covers ::blog_user_update */ public function test_blog_user_update() { + \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); $test_value = 'test value'; $result = \Activitypub\Scheduler\Actor::blog_user_update( $test_value ); @@ -160,7 +161,7 @@ public function test_schedule_post_activity_extra_fields() { * @covers ::schedule_post_activity */ public function test_schedule_post_activity_extra_field_blog() { - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_BLOG_MODE ); + \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); $blog_post_id = self::factory()->post->create( array( 'post_type' => Extra_Fields::BLOG_POST_TYPE ) ); $activitpub_id = Actors::get_by_id( Actors::BLOG_USER_ID )->get_id(); @@ -169,6 +170,5 @@ public function test_schedule_post_activity_extra_field_blog() { // Clean up. \wp_delete_post( $blog_post_id, true ); - \update_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); } } diff --git a/tests/includes/scheduler/class-test-post.php b/tests/includes/scheduler/class-test-post.php index b814f4ca4..d4735b96e 100644 --- a/tests/includes/scheduler/class-test-post.php +++ b/tests/includes/scheduler/class-test-post.php @@ -20,7 +20,7 @@ class Test_Post extends \Activitypub\Tests\ActivityPub_Outbox_TestCase { * @covers ::schedule_post_activity */ public function test_schedule_post_activity_regular_post() { - $post_id = self::factory()->post->create(); + $post_id = self::factory()->post->create( array( 'post_author' => self::$user_id ) ); $activitpub_id = \add_query_arg( 'p', $post_id, \home_url( '/' ) ); $post = $this->get_latest_outbox_item( $activitpub_id );