Follower object should not make any remote calls

This commit is contained in:
Matthias Pfefferle 2023-04-27 09:57:50 +02:00
parent b8c86915b5
commit ec822535c9
5 changed files with 105 additions and 54 deletions

View file

@ -10,6 +10,7 @@ use Activitypub\Model\Follower;
use function Activitypub\safe_remote_get; use function Activitypub\safe_remote_get;
use function Activitypub\safe_remote_post; use function Activitypub\safe_remote_post;
use function Activitypub\get_remote_metadata_by_actor;
/** /**
* ActivityPub Followers Collection * ActivityPub Followers Collection
@ -193,7 +194,14 @@ class Followers {
* @return array|WP_Error The Follower (WP_Term array) or an WP_Error * @return array|WP_Error The Follower (WP_Term array) or an WP_Error
*/ */
public static function add_follower( $user_id, $actor ) { 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 = new Follower( $actor );
$follower->from_meta( $meta );
$follower->upsert(); $follower->upsert();
$result = wp_set_object_terms( $user_id, $follower->get_actor(), self::TAXONOMY, true ); $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 * @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 ) { public static function get_followers( $user_id, $output = ARRAY_N, $number = null, $offset = null ) {
//self::migrate_followers( $user_id );
$terms = new WP_Term_Query( $terms = new WP_Term_Query(
array( array(
'taxonomy' => self::TAXONOMY, 'taxonomy' => self::TAXONOMY,

View file

@ -102,12 +102,10 @@ function get_webfinger_resource( $user_id ) {
* Requests the Meta-Data from the Actors profile * Requests the Meta-Data from the Actors profile
* *
* @param string $actor The Actor URL * @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 * @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 ); $pre = apply_filters( 'pre_get_remote_metadata_by_actor', false, $actor );
if ( $pre ) { if ( $pre ) {
return $pre; return $pre;
@ -161,9 +159,7 @@ function get_remote_metadata_by_actor( $actor, $cache = false ) {
$metadata = \wp_remote_retrieve_body( $response ); $metadata = \wp_remote_retrieve_body( $response );
$metadata = \json_decode( $metadata, true ); $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 ) { if ( ! $metadata ) {
$metadata = new \WP_Error( 'activitypub_invalid_json', \__( 'No valid JSON data', 'activitypub' ), $actor ); $metadata = new \WP_Error( 'activitypub_invalid_json', \__( 'No valid JSON data', 'activitypub' ), $actor );

View file

@ -3,8 +3,6 @@ namespace Activitypub\Model;
use Activitypub\Collection\Followers; use Activitypub\Collection\Followers;
use function Activitypub\get_remote_metadata_by_actor;
/** /**
* ActivityPub Follower Class * ActivityPub Follower Class
* *
@ -111,16 +109,14 @@ class Follower {
* @param WP_Post $post * @param WP_Post $post
*/ */
public function __construct( $actor ) { public function __construct( $actor ) {
$term = get_term_by( 'name', $actor, Followers::TAXONOMY );
$this->actor = $actor; $this->actor = $actor;
$term = get_term_by( 'name', $actor, Followers::TAXONOMY );
if ( $term ) { if ( $term ) {
$this->id = $term->term_id; $this->id = $term->term_id;
$this->slug = $term->slug; $this->slug = $term->slug;
$this->meta = json_decode( $term->meta ); $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 ) { public function get( $attribute ) {
if ( $this->$attribute ) { if ( $this->$attribute ) {
return $this->$attribute; return $this->$attribute;
} }
if ( ! $this->id ) { $attribute = get_term_meta( $this->id, $attribute, true );
$this->$attribute = $this->get_meta_by( $attribute ); if ( $attribute ) {
return $this->$attribute; $this->$attribute = $attribute;
return $attribute;
} }
$this->$attribute = get_term_meta( $this->id, $attribute, true ); $attribute = $this->get_meta_by( $attribute );
return $this->$attribute; if ( $attribute ) {
$this->$attribute = $attribute;
return $attribute;
} }
public function get_meta_by( $attribute, $force = false ) { return null;
$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 ) { foreach ( $this->map_meta as $remote => $local ) {
if ( $attribute === $local && isset( $meta[ $remote ] ) ) { if ( $attribute === $local && isset( $meta[ $remote ] ) ) {
return $meta[ $remote ]; return $meta[ $remote ];
} }
} }
// try ActivityPub attribtes
if ( ! empty( $this->map_meta[ $attribute ] ) ) {
return $this->map_meta[ $attribute ];
}
return null; return null;
} }
public function get_meta( $force = false ) { public function get_meta() {
if ( $this->meta && false === (bool) $force ) { if ( $this->meta ) {
return $this->meta; return $this->meta;
} }
$remote_data = get_remote_metadata_by_actor( $this->actor ); return null;
if ( ! $remote_data || is_wp_error( $remote_data ) || ! is_array( $remote_data ) ) {
$remote_data = array();
}
$this->meta = $remote_data;
return $this->meta;
} }
public function update() { public function update() {
@ -225,28 +247,12 @@ class Follower {
} }
protected function update_term_meta() { 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 ) { foreach ( $attributes as $attribute ) {
if ( ! empty( $meta[ $remote ] ) ) { if ( $this->get( $attribute ) ) {
update_term_meta( $this->id, $internal, $meta[ $remote ], true ); update_term_meta( $this->id, $attribute, $this->get( $attribute ), true );
$this->$internal = $meta[ $remote ];
} }
} }
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 );
} }
} }

View file

@ -77,6 +77,14 @@ class Followers extends WP_List_Table {
); );
} }
public function column_identifier( $item ) {
return sprintf(
'<a href="%s" target="_blank">%s</a>',
$item['identifier'],
$item['identifier']
);
}
public function column_cb( $item ) { public function column_cb( $item ) {
return sprintf( '<input type="checkbox" name="followers[]" value="%s" />', esc_attr( $item['identifier'] ) ); return sprintf( '<input type="checkbox" name="followers[]" value="%s" />', esc_attr( $item['identifier'] ) );
} }

View file

@ -13,14 +13,37 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
'name' => 'jon', 'name' => 'jon',
'prefferedUsername' => '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( 'sally@example.org' => array(
'url' => 'http://sally.example.org', 'url' => 'http://sally.example.org',
'inbox' => 'http://sally.example.org/inbox', 'inbox' => 'http://sally.example.org/inbox',
'name' => 'jon', 'name' => 'jon',
'prefferedUsername' => '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() { public function test_get_followers() {
$followers = array( 'https://example.com/author/jon', 'https://example.org/author/doe', 'http://sally.example.org' ); $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 ); add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
foreach ( $followers as $follower ) { 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 ); $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(); $pre_http_request = new MockAction();
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); 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 ); \Activitypub\Collection\Followers::add_follower( 1, $follower );
$db_followers = \Activitypub\Collection\Followers::get_followers( 1 ); $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 ) { public static function http_response( $response, $args, $url ) {
return $response; 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;
}
} }