From e015da7f8f258d193ce1950e14be3123a44aee5a Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 01:42:15 +0100 Subject: [PATCH 1/7] optimize publishing --- includes/class-activity-dispatcher.php | 78 +++++++++----------------- includes/class-activitypub.php | 2 +- includes/functions.php | 5 +- includes/model/class-activity.php | 17 +++++- includes/model/class-post.php | 2 +- 5 files changed, 48 insertions(+), 56 deletions(-) diff --git a/includes/class-activity-dispatcher.php b/includes/class-activity-dispatcher.php index f8abd38..09fca79 100644 --- a/includes/class-activity-dispatcher.php +++ b/includes/class-activity-dispatcher.php @@ -13,7 +13,10 @@ class Activity_Dispatcher { * Initialize the class, registering WordPress hooks. */ public static function init() { - \add_action( 'activitypub_send_post_activity', array( '\Activitypub\Activity_Dispatcher', 'send_post_activity' ) ); + // legacy + \add_action( 'activitypub_send_post_activity', array( '\Activitypub\Activity_Dispatcher', 'send_create_activity' ) ); + + \add_action( 'activitypub_send_create_activity', array( '\Activitypub\Activity_Dispatcher', 'send_create_activity' ) ); \add_action( 'activitypub_send_update_activity', array( '\Activitypub\Activity_Dispatcher', 'send_update_activity' ) ); \add_action( 'activitypub_send_delete_activity', array( '\Activitypub\Activity_Dispatcher', 'send_delete_activity' ) ); } @@ -23,38 +26,8 @@ class Activity_Dispatcher { * * @param \Activitypub\Model\Post $activitypub_post */ - public static function send_post_activity( Model\Post $activitypub_post ) { - // get latest version of post - $user_id = $activitypub_post->get_post_author(); - - $activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL ); - $activitypub_activity->from_post( $activitypub_post ); - - $inboxes = \Activitypub\get_follower_inboxes( $user_id ); - - $followers_url = \get_rest_url( null, '/activitypub/1.0/users/' . intval( $user_id ) . '/followers' ); - foreach ( $activitypub_activity->get_cc() as $cc ) { - if ( $cc === $followers_url ) { - continue; - } - $inbox = \Activitypub\get_inbox_by_actor( $cc ); - if ( ! $inbox || \is_wp_error( $inbox ) ) { - continue; - } - // init array if empty - if ( ! isset( $inboxes[ $inbox ] ) ) { - $inboxes[ $inbox ] = array(); - } - $inboxes[ $inbox ][] = $cc; - } - - foreach ( $inboxes as $inbox => $to ) { - $to = array_values( array_unique( $to ) ); - $activitypub_activity->set_to( $to ); - $activity = $activitypub_activity->to_json(); - - \Activitypub\safe_remote_post( $inbox, $activity, $user_id ); - } + public static function send_create_activity( Model\Post $activitypub_post ) { + self::send_activity( $activitypub_post, 'Create' ); } /** @@ -62,19 +35,8 @@ class Activity_Dispatcher { * * @param \Activitypub\Model\Post $activitypub_post */ - public static function send_update_activity( $activitypub_post ) { - // get latest version of post - $user_id = $activitypub_post->get_post_author(); - - $activitypub_activity = new \Activitypub\Model\Activity( 'Update', \Activitypub\Model\Activity::TYPE_FULL ); - $activitypub_activity->from_post( $activitypub_post ); - - foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) { - $activitypub_activity->set_to( $to ); - $activity = $activitypub_activity->to_json(); // phpcs:ignore - - \Activitypub\safe_remote_post( $inbox, $activity, $user_id ); - } + public static function send_update_activity( Model\Post $activitypub_post ) { + self::send_activity( $activitypub_post, 'Update' ); } /** @@ -82,16 +44,30 @@ class Activity_Dispatcher { * * @param \Activitypub\Model\Post $activitypub_post */ - public static function send_delete_activity( $activitypub_post ) { + public static function send_delete_activity( Model\Post $activitypub_post ) { + self::send_activity( $activitypub_post, 'Delete' ); + } + + /** + * Undocumented function + * + * @param [type] $activitypub_post + * @param [type] $activity_type + * @return void + */ + public function send_activity( Model\Post $activitypub_post, $activity_type ) { // get latest version of post $user_id = $activitypub_post->get_post_author(); - $activitypub_activity = new \Activitypub\Model\Activity( 'Delete', \Activitypub\Model\Activity::TYPE_FULL ); + $activitypub_activity = new \Activitypub\Model\Activity( $activity_type, \Activitypub\Model\Activity::TYPE_FULL ); $activitypub_activity->from_post( $activitypub_post ); - foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) { - $activitypub_activity->set_to( $to ); - $activity = $activitypub_activity->to_json(); // phpcs:ignore + $inboxes = \Activitypub\get_follower_inboxes( $user_id, $activitypub_activity->get_cc() ); + + foreach ( $inboxes as $inbox => $cc ) { + $cc = array_values( array_unique( $cc ) ); + $activitypub_activity->add_cc( $cc ); + $activity = $activitypub_activity->to_json(); \Activitypub\safe_remote_post( $inbox, $activity, $user_id ); } diff --git a/includes/class-activitypub.php b/includes/class-activitypub.php index c04aedc..4a60915 100644 --- a/includes/class-activitypub.php +++ b/includes/class-activitypub.php @@ -117,7 +117,7 @@ class Activitypub { $activitypub_post = new \Activitypub\Model\Post( $post ); if ( 'publish' === $new_status && 'publish' !== $old_status ) { - \wp_schedule_single_event( \time(), 'activitypub_send_post_activity', array( $activitypub_post ) ); + \wp_schedule_single_event( \time(), 'activitypub_send_create_activity', array( $activitypub_post ) ); } elseif ( 'publish' === $new_status ) { \wp_schedule_single_event( \time(), 'activitypub_send_update_activity', array( $activitypub_post ) ); } elseif ( 'trash' === $new_status ) { diff --git a/includes/functions.php b/includes/functions.php index 8f2e5d9..77508c5 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -219,8 +219,11 @@ function get_publickey_by_actor( $actor, $key_id ) { return new \WP_Error( 'activitypub_no_public_key', \__( 'No "Public-Key" found', 'activitypub' ), $metadata ); } -function get_follower_inboxes( $user_id ) { +function get_follower_inboxes( $user_id, $cc = array() ) { $followers = \Activitypub\Peer\Followers::get_followers( $user_id ); + $followers = array_merge( $followers, $cc ); + $followers = array_unique( $followers ); + $inboxes = array(); foreach ( $followers as $follower ) { diff --git a/includes/model/class-activity.php b/includes/model/class-activity.php index f865d6d..c95e6ff 100644 --- a/includes/model/class-activity.php +++ b/includes/model/class-activity.php @@ -43,6 +43,18 @@ class Activity { if ( \strncasecmp( $method, 'set', 3 ) === 0 ) { $this->$var = $params[0]; } + + if ( \strncasecmp( $method, 'add', 3 ) === 0 ) { + if ( ! is_array( $this->$var ) ) { + $this->$var = $params[0]; + } + + if ( is_array( $params[0] ) ) { + $this->$var = array_merge( $this->$var, $params[0] ); + } else { + array_push( $this->$var, $params[0] ); + } + } } public function from_post( Post $post ) { @@ -51,7 +63,8 @@ class Activity { if ( isset( $object['published'] ) ) { $this->published = $object['published']; } - $this->cc = array( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $post->get_post_author() ) . '/followers' ) ); + + $this->add_to( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $post->get_post_author() ) . '/followers' ) ); if ( isset( $this->object['attributedTo'] ) ) { $this->actor = $this->object['attributedTo']; @@ -59,7 +72,7 @@ class Activity { foreach ( $post->get_tags() as $tag ) { if ( 'Mention' === $tag['type'] ) { - $this->cc[] = $tag['href']; + $this->add_cc( $tag['href'] ); } } diff --git a/includes/model/class-post.php b/includes/model/class-post.php index 543a890..5d2ac48 100644 --- a/includes/model/class-post.php +++ b/includes/model/class-post.php @@ -386,7 +386,7 @@ class Post { $filtered_content = \apply_filters( 'activitypub_the_content', $content, $post ); $decoded_content = \html_entity_decode( $filtered_content, \ENT_QUOTES, 'UTF-8' ); - $content = \trim( \preg_replace( '/[\n\r]/', '', $content ) ); + $content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) ); $this->content = $content; From 472ee27849c561b241caac44cb04bdb827768abf Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 01:47:12 +0100 Subject: [PATCH 2/7] fix unit tests --- tests/test-class-activitypub-activity-dispatcher.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test-class-activitypub-activity-dispatcher.php b/tests/test-class-activitypub-activity-dispatcher.php index 6693ba1..ec62b2d 100644 --- a/tests/test-class-activitypub-activity-dispatcher.php +++ b/tests/test-class-activitypub-activity-dispatcher.php @@ -28,7 +28,7 @@ class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HT add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); $activitypub_post = new \Activitypub\Model\Post( $post ); - \Activitypub\Activity_Dispatcher::send_post_activity( $activitypub_post ); + \Activitypub\Activity_Dispatcher::send_create_activity( $activitypub_post ); $this->assertSame( 2, $pre_http_request->get_call_count() ); $all_args = $pre_http_request->get_args(); @@ -67,7 +67,7 @@ class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HT add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); $activitypub_post = new \Activitypub\Model\Post( $post ); - \Activitypub\Activity_Dispatcher::send_post_activity( $activitypub_post ); + \Activitypub\Activity_Dispatcher::send_create_activity( $activitypub_post ); $this->assertSame( 1, $pre_http_request->get_call_count() ); $all_args = $pre_http_request->get_args(); From 3c84be1691b7388e57d942911c0973671a0309c4 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 01:50:20 +0100 Subject: [PATCH 3/7] fix unit tests --- includes/class-activity-dispatcher.php | 2 +- tests/test-class-activitypub-activity.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/class-activity-dispatcher.php b/includes/class-activity-dispatcher.php index 09fca79..221e2b0 100644 --- a/includes/class-activity-dispatcher.php +++ b/includes/class-activity-dispatcher.php @@ -55,7 +55,7 @@ class Activity_Dispatcher { * @param [type] $activity_type * @return void */ - public function send_activity( Model\Post $activitypub_post, $activity_type ) { + public static function send_activity( Model\Post $activitypub_post, $activity_type ) { // get latest version of post $user_id = $activitypub_post->get_post_author(); diff --git a/tests/test-class-activitypub-activity.php b/tests/test-class-activitypub-activity.php index 254d860..74d0727 100644 --- a/tests/test-class-activitypub-activity.php +++ b/tests/test-class-activitypub-activity.php @@ -22,7 +22,7 @@ class Test_Activitypub_Activity extends WP_UnitTestCase { $activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL ); $activitypub_activity->from_post( $activitypub_post ); - $this->assertContains( \get_rest_url( null, '/activitypub/1.0/users/1/followers' ), $activitypub_activity->get_cc() ); + $this->assertContains( \get_rest_url( null, '/activitypub/1.0/users/1/followers' ), $activitypub_activity->get_to() ); $this->assertContains( 'https://example.com/alex', $activitypub_activity->get_cc() ); remove_all_filters( 'activitypub_extract_mentions' ); From e52181fd3733b6b9b126f5ce046bbe10207ea312 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 02:04:06 +0100 Subject: [PATCH 4/7] fix tests --- includes/model/class-activity.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/includes/model/class-activity.php b/includes/model/class-activity.php index c95e6ff..220541e 100644 --- a/includes/model/class-activity.php +++ b/includes/model/class-activity.php @@ -15,7 +15,7 @@ class Activity { private $type = 'Create'; private $actor = ''; private $to = array( 'https://www.w3.org/ns/activitystreams#Public' ); - private $cc = array( 'https://www.w3.org/ns/activitystreams#Public' ); + private $cc = array(); private $object = null; const TYPE_SIMPLE = 'simple'; @@ -54,6 +54,8 @@ class Activity { } else { array_push( $this->$var, $params[0] ); } + + $this->$var = array_unique( $this->$var ); } } From 365d5dd4997c22d7e6c2ef14a8e68e5a0bd36f7d Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 02:35:57 +0100 Subject: [PATCH 5/7] fix outbox --- includes/rest/class-outbox.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/rest/class-outbox.php b/includes/rest/class-outbox.php index 7eec5ac..677e2ff 100644 --- a/includes/rest/class-outbox.php +++ b/includes/rest/class-outbox.php @@ -102,8 +102,8 @@ class Outbox { foreach ( $posts as $post ) { $activitypub_post = new \Activitypub\Model\Post( $post ); - $activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_NONE ); - $activitypub_activity->from_post( $activitypub_post->to_array() ); + $activitypub_activity = new \Activitypub\Model\Activity( 'Create', false ); + $activitypub_activity->from_post( $activitypub_post ); $json->orderedItems[] = $activitypub_activity->to_array(); // phpcs:ignore } } From de32cb7b7320bfa6fac5603ea7978059c1e83579 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 02:36:29 +0100 Subject: [PATCH 6/7] add changes also to the object --- includes/class-activity-dispatcher.php | 2 +- includes/model/class-activity.php | 32 ++++++++++++++++------- includes/model/class-post.php | 22 ++++++++++++++-- includes/rest/class-inbox.php | 2 +- tests/test-class-activitypub-activity.php | 2 +- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/includes/class-activity-dispatcher.php b/includes/class-activity-dispatcher.php index 221e2b0..6df83e7 100644 --- a/includes/class-activity-dispatcher.php +++ b/includes/class-activity-dispatcher.php @@ -59,7 +59,7 @@ class Activity_Dispatcher { // get latest version of post $user_id = $activitypub_post->get_post_author(); - $activitypub_activity = new \Activitypub\Model\Activity( $activity_type, \Activitypub\Model\Activity::TYPE_FULL ); + $activitypub_activity = new \Activitypub\Model\Activity( $activity_type ); $activitypub_activity->from_post( $activitypub_post ); $inboxes = \Activitypub\get_follower_inboxes( $user_id, $activitypub_activity->get_cc() ); diff --git a/includes/model/class-activity.php b/includes/model/class-activity.php index 220541e..34f6146 100644 --- a/includes/model/class-activity.php +++ b/includes/model/class-activity.php @@ -9,7 +9,27 @@ namespace Activitypub\Model; * @see https://www.w3.org/TR/activitypub/ */ class Activity { - private $context = array( 'https://www.w3.org/ns/activitystreams' ); + private $context = array( + 'https://www.w3.org/ns/activitystreams', + 'https://w3id.org/security/v1', + array( + 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', + 'PropertyValue' => 'schema:PropertyValue', + 'schema' => 'http://schema.org#', + 'pt' => 'https://joinpeertube.org/ns#', + 'toot' => 'http://joinmastodon.org/ns#', + 'value' => 'schema:value', + 'Hashtag' => 'as:Hashtag', + 'featured' => array( + '@id' => 'toot:featured', + '@type' => '@id', + ), + 'featuredTags' => array( + '@id' => 'toot:featuredTags', + '@type' => '@id', + ), + ), + ); private $published = ''; private $id = ''; private $type = 'Create'; @@ -18,15 +38,9 @@ class Activity { private $cc = array(); private $object = null; - const TYPE_SIMPLE = 'simple'; - const TYPE_FULL = 'full'; - const TYPE_NONE = 'none'; - - public function __construct( $type = 'Create', $context = self::TYPE_SIMPLE ) { - if ( 'none' === $context ) { + public function __construct( $type = 'Create', $context = true ) { + if ( true !== $context ) { $this->context = null; - } elseif ( 'full' === $context ) { - $this->context = \Activitypub\get_context(); } $this->type = \ucfirst( $type ); diff --git a/includes/model/class-post.php b/includes/model/class-post.php index 5d2ac48..90f19ef 100644 --- a/includes/model/class-post.php +++ b/includes/model/class-post.php @@ -87,6 +87,9 @@ class Post { ), ); + private $to = array( 'https://www.w3.org/ns/activitystreams#Public' ); + private $cc = array(); + /** * Constructor * @@ -94,6 +97,7 @@ class Post { */ public function __construct( $post ) { $this->post = \get_post( $post ); + $this->add_to( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $this->get_post_author() ) . '/followers' ) ); } /** @@ -117,6 +121,20 @@ class Post { if ( \strncasecmp( $method, 'set', 3 ) === 0 ) { $this->$var = $params[0]; } + + if ( \strncasecmp( $method, 'add', 3 ) === 0 ) { + if ( ! is_array( $this->$var ) ) { + $this->$var = $params[0]; + } + + if ( is_array( $params[0] ) ) { + $this->$var = array_merge( $this->$var, $params[0] ); + } else { + array_push( $this->$var, $params[0] ); + } + + $this->$var = array_unique( $this->$var ); + } } /** @@ -138,8 +156,8 @@ class Post { 'contentMap' => array( \strstr( \get_locale(), '_', true ) => $this->get_content(), ), - 'to' => array( 'https://www.w3.org/ns/activitystreams#Public' ), - 'cc' => array( 'https://www.w3.org/ns/activitystreams#Public' ), + 'to' => $this->get_to(), + 'cc' => $this->get_cc(), 'attachment' => $this->get_attachments(), 'tag' => $this->get_tags(), ); diff --git a/includes/rest/class-inbox.php b/includes/rest/class-inbox.php index 5c21f43..1eab8a5 100644 --- a/includes/rest/class-inbox.php +++ b/includes/rest/class-inbox.php @@ -356,7 +356,7 @@ class Inbox { $inbox = \Activitypub\get_inbox_by_actor( $object['actor'] ); // send "Accept" activity - $activity = new \Activitypub\Model\Activity( 'Accept', \Activitypub\Model\Activity::TYPE_SIMPLE ); + $activity = new \Activitypub\Model\Activity( 'Accept' ); $activity->set_object( $object ); $activity->set_actor( \get_author_posts_url( $user_id ) ); $activity->set_to( $object['actor'] ); diff --git a/tests/test-class-activitypub-activity.php b/tests/test-class-activitypub-activity.php index 74d0727..7fe6551 100644 --- a/tests/test-class-activitypub-activity.php +++ b/tests/test-class-activitypub-activity.php @@ -19,7 +19,7 @@ class Test_Activitypub_Activity extends WP_UnitTestCase { $activitypub_post = new \Activitypub\Model\Post( $post ); - $activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL ); + $activitypub_activity = new \Activitypub\Model\Activity( 'Create' ); $activitypub_activity->from_post( $activitypub_post ); $this->assertContains( \get_rest_url( null, '/activitypub/1.0/users/1/followers' ), $activitypub_activity->get_to() ); From 73ae47e37729047088bb34dbff618ca76468b3c8 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 2 Feb 2023 07:24:27 +0100 Subject: [PATCH 7/7] PHPDoc --- includes/model/class-post.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/includes/model/class-post.php b/includes/model/class-post.php index 90f19ef..0929277 100644 --- a/includes/model/class-post.php +++ b/includes/model/class-post.php @@ -87,7 +87,22 @@ class Post { ), ); + /** + * List of audience + * + * Also used for visibility + * + * @var array + */ private $to = array( 'https://www.w3.org/ns/activitystreams#Public' ); + + /** + * List of audience + * + * Also used for visibility + * + * @var array + */ private $cc = array(); /**