From ec822535c9d49e1fc563facd42df0531c6f35d08 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Thu, 27 Apr 2023 09:57:50 +0200 Subject: [PATCH] Follower object should not make any remote calls --- includes/collection/class-followers.php | 10 +- includes/functions.php | 8 +- includes/model/class-follower.php | 94 ++++++++++--------- includes/table/class-followers.php | 8 ++ tests/test-class-db-activitypub-followers.php | 39 +++++++- 5 files changed, 105 insertions(+), 54 deletions(-) diff --git a/includes/collection/class-followers.php b/includes/collection/class-followers.php index cd7f5f7..3eb09d8 100644 --- a/includes/collection/class-followers.php +++ b/includes/collection/class-followers.php @@ -10,6 +10,7 @@ use Activitypub\Model\Follower; use function Activitypub\safe_remote_get; use function Activitypub\safe_remote_post; +use function Activitypub\get_remote_metadata_by_actor; /** * ActivityPub Followers Collection @@ -193,7 +194,14 @@ class Followers { * @return array|WP_Error The Follower (WP_Term array) or an WP_Error */ public static function add_follower( $user_id, $actor ) { + $meta = get_remote_metadata_by_actor( $actor ); + + if ( ! $meta || is_wp_error( $meta ) || ! is_array( $meta ) ) { + return $meta; + } + $follower = new Follower( $actor ); + $follower->from_meta( $meta ); $follower->upsert(); $result = wp_set_object_terms( $user_id, $follower->get_actor(), self::TAXONOMY, true ); @@ -286,8 +294,6 @@ class Followers { * @return array The Term list of Followers, the format depends on $output */ public static function get_followers( $user_id, $output = ARRAY_N, $number = null, $offset = null ) { - //self::migrate_followers( $user_id ); - $terms = new WP_Term_Query( array( 'taxonomy' => self::TAXONOMY, diff --git a/includes/functions.php b/includes/functions.php index 09d3911..3a457a9 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -102,12 +102,10 @@ function get_webfinger_resource( $user_id ) { * Requests the Meta-Data from the Actors profile * * @param string $actor The Actor URL - * @param bool $cache Enable/Disable caching of the meta. - * This does not effect Error-Caching. * * @return array The Actor profile as array */ -function get_remote_metadata_by_actor( $actor, $cache = false ) { +function get_remote_metadata_by_actor( $actor ) { $pre = apply_filters( 'pre_get_remote_metadata_by_actor', false, $actor ); if ( $pre ) { return $pre; @@ -161,9 +159,7 @@ function get_remote_metadata_by_actor( $actor, $cache = false ) { $metadata = \wp_remote_retrieve_body( $response ); $metadata = \json_decode( $metadata, true ); - if ( true === $cache ) { - \set_transient( $transient_key, $metadata, WEEK_IN_SECONDS ); - } + \set_transient( $transient_key, $metadata, WEEK_IN_SECONDS ); if ( ! $metadata ) { $metadata = new \WP_Error( 'activitypub_invalid_json', \__( 'No valid JSON data', 'activitypub' ), $actor ); diff --git a/includes/model/class-follower.php b/includes/model/class-follower.php index f3f8f7b..d4fc70f 100644 --- a/includes/model/class-follower.php +++ b/includes/model/class-follower.php @@ -3,8 +3,6 @@ namespace Activitypub\Model; use Activitypub\Collection\Followers; -use function Activitypub\get_remote_metadata_by_actor; - /** * ActivityPub Follower Class * @@ -111,16 +109,14 @@ class Follower { * @param WP_Post $post */ public function __construct( $actor ) { - $term = get_term_by( 'name', $actor, Followers::TAXONOMY ); - $this->actor = $actor; + $term = get_term_by( 'name', $actor, Followers::TAXONOMY ); + if ( $term ) { $this->id = $term->term_id; $this->slug = $term->slug; $this->meta = json_decode( $term->meta ); - } else { - $this->slug = sanitize_title( $actor ); } } @@ -147,46 +143,72 @@ class Follower { } } + public function from_meta( $meta ) { + $this->meta = $meta; + + foreach ( $this->map_meta as $remote => $internal ) { + if ( ! empty( $meta[ $remote ] ) ) { + $this->$internal = $meta[ $remote ]; + } + } + + if ( ! empty( $meta['icon']['url'] ) ) { + $this->avatar = $meta['icon']['url']; + } + + if ( ! empty( $meta['endpoints']['sharedInbox'] ) ) { + $this->shared_inbox = $meta['endpoints']['sharedInbox']; + } elseif ( ! empty( $meta['inbox'] ) ) { + $this->shared_inbox = $meta['inbox']; + } + + $this->updated_at = \strtotime( 'now' ); + } + public function get( $attribute ) { if ( $this->$attribute ) { return $this->$attribute; } - if ( ! $this->id ) { - $this->$attribute = $this->get_meta_by( $attribute ); - return $this->$attribute; + $attribute = get_term_meta( $this->id, $attribute, true ); + if ( $attribute ) { + $this->$attribute = $attribute; + return $attribute; } - $this->$attribute = get_term_meta( $this->id, $attribute, true ); - return $this->$attribute; + $attribute = $this->get_meta_by( $attribute ); + if ( $attribute ) { + $this->$attribute = $attribute; + return $attribute; + } + + return null; } - public function get_meta_by( $attribute, $force = false ) { - $meta = $this->get_meta( $force ); + public function get_meta_by( $attribute ) { + $meta = $this->get_meta(); + // try mapped data ($this->map_meta) foreach ( $this->map_meta as $remote => $local ) { if ( $attribute === $local && isset( $meta[ $remote ] ) ) { return $meta[ $remote ]; } } + // try ActivityPub attribtes + if ( ! empty( $this->map_meta[ $attribute ] ) ) { + return $this->map_meta[ $attribute ]; + } + return null; } - public function get_meta( $force = false ) { - if ( $this->meta && false === (bool) $force ) { + public function get_meta() { + if ( $this->meta ) { return $this->meta; } - $remote_data = get_remote_metadata_by_actor( $this->actor ); - - if ( ! $remote_data || is_wp_error( $remote_data ) || ! is_array( $remote_data ) ) { - $remote_data = array(); - } - - $this->meta = $remote_data; - - return $this->meta; + return null; } public function update() { @@ -225,28 +247,12 @@ class Follower { } protected function update_term_meta() { - $meta = $this->get_meta(); + $attributes = array( 'inbox', 'shared_inbox', 'avatar', 'updated_at', 'name', 'username' ); - foreach ( $this->map_meta as $remote => $internal ) { - if ( ! empty( $meta[ $remote ] ) ) { - update_term_meta( $this->id, $internal, $meta[ $remote ], true ); - $this->$internal = $meta[ $remote ]; + foreach ( $attributes as $attribute ) { + if ( $this->get( $attribute ) ) { + update_term_meta( $this->id, $attribute, $this->get( $attribute ), true ); } } - - if ( ! empty( $meta['icon']['url'] ) ) { - update_term_meta( $this->id, 'avatar', $meta['icon']['url'], true ); - $this->avatar = $meta['icon']['url']; - } - - if ( ! empty( $meta['endpoints']['sharedInbox'] ) ) { - update_term_meta( $this->id, 'shared_inbox', $meta['endpoints']['sharedInbox'], true ); - $this->shared_inbox = $meta['endpoints']['sharedInbox']; - } elseif ( ! empty( $meta['inbox'] ) ) { - update_term_meta( $this->id, 'shared_inbox', $meta['inbox'], true ); - $this->shared_inbox = $meta['inbox']; - } - - update_term_meta( $this->id, 'updated_at', \strtotime( 'now' ), true ); } } diff --git a/includes/table/class-followers.php b/includes/table/class-followers.php index 13d6a91..c39b45f 100644 --- a/includes/table/class-followers.php +++ b/includes/table/class-followers.php @@ -77,6 +77,14 @@ class Followers extends WP_List_Table { ); } + public function column_identifier( $item ) { + return sprintf( + '%s', + $item['identifier'], + $item['identifier'] + ); + } + public function column_cb( $item ) { return sprintf( '', esc_attr( $item['identifier'] ) ); } diff --git a/tests/test-class-db-activitypub-followers.php b/tests/test-class-db-activitypub-followers.php index 97318d4..640c4d1 100644 --- a/tests/test-class-db-activitypub-followers.php +++ b/tests/test-class-db-activitypub-followers.php @@ -13,14 +13,37 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase { 'name' => 'jon', 'prefferedUsername' => 'jon', ), + 'doe@example.org' => array( + 'url' => 'https://example.org/author/doe', + 'inbox' => 'https://example.org/author/doe/inbox', + 'name' => 'doe', + 'prefferedUsername' => 'doe', + ), 'sally@example.org' => array( 'url' => 'http://sally.example.org', 'inbox' => 'http://sally.example.org/inbox', 'name' => 'jon', 'prefferedUsername' => 'jon', ), + '12345@example.com' => array( + 'url' => 'https://12345.example.com', + 'inbox' => 'https://12345.example.com/inbox', + 'name' => '12345', + 'prefferedUsername' => '12345', + ), ); + public function set_up() { + parent::set_up(); + add_filter( 'pre_get_remote_metadata_by_actor', array( get_called_class(), 'pre_get_remote_metadata_by_actor' ), 10, 2 ); + _delete_all_posts(); + } + + public function tear_down() { + remove_filter( 'pre_get_remote_metadata_by_actor', array( get_called_class(), 'pre_get_remote_metadata_by_actor' ) ); + parent::tear_down(); + } + public function test_get_followers() { $followers = array( 'https://example.com/author/jon', 'https://example.org/author/doe', 'http://sally.example.org' ); @@ -28,7 +51,7 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase { add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); foreach ( $followers as $follower ) { - \Activitypub\Collection\Followers::add_follower( 1, $follower ); + $response = \Activitypub\Collection\Followers::add_follower( 1, $follower ); } $db_followers = \Activitypub\Collection\Followers::get_followers( 1 ); @@ -42,7 +65,7 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase { $pre_http_request = new MockAction(); add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); - $follower = 'https://example.com/author/' . \time(); + $follower = 'https://12345.example.com'; \Activitypub\Collection\Followers::add_follower( 1, $follower ); $db_followers = \Activitypub\Collection\Followers::get_followers( 1 ); @@ -95,4 +118,16 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase { public static function http_response( $response, $args, $url ) { return $response; } + + public static function pre_get_remote_metadata_by_actor( $pre, $actor ) { + if ( isset( self::$users[ $actor ] ) ) { + return self::$users[ $actor ]; + } + foreach ( self::$users as $username => $data ) { + if ( $data['url'] === $actor ) { + return $data; + } + } + return $pre; + } }