6e7f82bf42
* init * save source id * fix delete and add improve undo * test new functions * add support for threaded comments * some formatting * check if URL is no longer available ...and returns either status 410 or 404. * improve delete handler * improve update handler * `object` and `actor` are already required by the inbox endpoint * fix typo * simplify queries * cosmetics * fix unit tests * schedule delete comments of deleted actor (#575) * schedule delete comments of deleted actor * phpcs --------- Co-authored-by: Django Doucet <django.doucet@webdevstudios.com> * move `get_comments_by_actor` to interactions collection * consistent wording * implement Tombstone * fix follow issue * fix inbox-create * added missing namespace * check if field is set * Fix namespacing issue * update profile and update interaction * fields are already validated by inbox * optimize avatar handling --------- Co-authored-by: Django <mediaformat.ux@gmail.com> Co-authored-by: Django Doucet <django.doucet@webdevstudios.com>
388 lines
13 KiB
PHP
388 lines
13 KiB
PHP
<?php
|
|
class Test_Activitypub_Followers extends WP_UnitTestCase {
|
|
public static $users = array(
|
|
'username@example.org' => array(
|
|
'id' => 'https://example.org/users/username',
|
|
'url' => 'https://example.org/users/username',
|
|
'inbox' => 'https://example.org/users/username/inbox',
|
|
'name' => 'username',
|
|
'preferredUsername' => 'username',
|
|
),
|
|
'jon@example.com' => array(
|
|
'id' => 'https://example.com/author/jon',
|
|
'url' => 'https://example.com/author/jon',
|
|
'inbox' => 'https://example.com/author/jon/inbox',
|
|
'name' => 'jon',
|
|
'preferredUsername' => 'jon',
|
|
),
|
|
'doe@example.org' => array(
|
|
'id' => 'https://example.org/author/doe',
|
|
'url' => 'https://example.org/author/doe',
|
|
'inbox' => 'https://example.org/author/doe/inbox',
|
|
'name' => 'doe',
|
|
'preferredUsername' => 'doe',
|
|
),
|
|
'sally@example.org' => array(
|
|
'id' => 'http://sally.example.org',
|
|
'url' => 'http://sally.example.org',
|
|
'inbox' => 'http://sally.example.org/inbox',
|
|
'name' => 'jon',
|
|
'preferredUsername' => 'jon',
|
|
),
|
|
'12345@example.com' => array(
|
|
'id' => 'https://12345.example.com',
|
|
'url' => 'https://12345.example.com',
|
|
'inbox' => 'https://12345.example.com/inbox',
|
|
'name' => '12345',
|
|
'preferredUsername' => '12345',
|
|
),
|
|
'user2@example.com' => array(
|
|
'id' => 'https://user2.example.com',
|
|
'url' => 'https://user2.example.com',
|
|
'inbox' => 'https://user2.example.com/inbox',
|
|
'name' => 'úser2',
|
|
'preferredUsername' => 'user2',
|
|
),
|
|
'error@example.com' => array(
|
|
'url' => 'https://error.example.com',
|
|
'name' => 'error',
|
|
'preferredUsername' => 'error',
|
|
),
|
|
);
|
|
|
|
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' );
|
|
|
|
$pre_http_request = new MockAction();
|
|
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
|
|
|
|
foreach ( $followers as $follower ) {
|
|
$response = \Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
}
|
|
|
|
$db_followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
|
|
|
$this->assertEquals( 3, \count( $db_followers ) );
|
|
|
|
$db_followers = array_map(
|
|
function( $item ) {
|
|
return $item->get_url();
|
|
},
|
|
$db_followers
|
|
);
|
|
|
|
$this->assertEquals( array( 'http://sally.example.org', 'https://example.org/author/doe', 'https://example.com/author/jon' ), $db_followers );
|
|
}
|
|
|
|
public function test_add_follower() {
|
|
$pre_http_request = new MockAction();
|
|
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
|
|
|
|
$follower = 'https://12345.example.com';
|
|
$follower2 = 'https://user2.example.com';
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
\Activitypub\Collection\Followers::add_follower( 2, $follower );
|
|
\Activitypub\Collection\Followers::add_follower( 2, $follower2 );
|
|
|
|
$db_followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
|
$db_followers2 = \Activitypub\Collection\Followers::get_followers( 2 );
|
|
|
|
$this->assertContains( $follower, $db_followers );
|
|
$this->assertContains( $follower2, $db_followers2 );
|
|
}
|
|
|
|
public function test_add_follower_error() {
|
|
$pre_http_request = new MockAction();
|
|
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
|
|
|
|
$follower = 'error@example.com';
|
|
|
|
$result = \Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
|
|
$this->assertTrue( is_wp_error( $result ) );
|
|
|
|
$follower2 = 'https://error.example.com';
|
|
|
|
$result = \Activitypub\Collection\Followers::add_follower( 1, $follower2 );
|
|
|
|
$this->assertTrue( is_wp_error( $result ) );
|
|
|
|
$db_followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
|
|
|
$this->assertEmpty( $db_followers );
|
|
}
|
|
|
|
public function test_get_follower() {
|
|
$followers = array( 'https://example.com/author/jon' );
|
|
$followers2 = array( 'https://user2.example.com' );
|
|
|
|
$pre_http_request = new MockAction();
|
|
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
|
|
|
|
foreach ( $followers as $follower ) {
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
}
|
|
|
|
foreach ( $followers2 as $follower ) {
|
|
\Activitypub\Collection\Followers::add_follower( 2, $follower );
|
|
}
|
|
|
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
|
$this->assertEquals( 'https://example.com/author/jon', $follower->get_url() );
|
|
|
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'http://sally.example.org' );
|
|
$this->assertNull( $follower );
|
|
|
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://user2.example.com' );
|
|
$this->assertNull( $follower );
|
|
|
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
|
$this->assertEquals( 'https://example.com/author/jon', $follower->get_url() );
|
|
|
|
$follower2 = \Activitypub\Collection\Followers::get_follower( 2, 'https://user2.example.com' );
|
|
$this->assertEquals( 'https://user2.example.com', $follower2->get_url() );
|
|
$this->assertEquals( 'úser2', $follower2->get_name() );
|
|
}
|
|
|
|
public function test_delete_follower() {
|
|
$followers = array(
|
|
'https://example.com/author/jon',
|
|
'https://example.org/author/doe',
|
|
);
|
|
$followers2 = array( 'https://user2.example.com' );
|
|
|
|
$pre_http_request = new MockAction();
|
|
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
|
|
|
|
foreach ( $followers as $follower ) {
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
\Activitypub\Collection\Followers::add_follower( 2, $follower );
|
|
}
|
|
|
|
foreach ( $followers2 as $follower2 ) {
|
|
\Activitypub\Collection\Followers::add_follower( 2, $follower2 );
|
|
}
|
|
|
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
|
$this->assertEquals( 'https://example.com/author/jon', $follower->get_url() );
|
|
|
|
$followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
|
$this->assertEquals( 2, count( $followers ) );
|
|
|
|
$follower2 = \Activitypub\Collection\Followers::get_follower( 2, 'https://example.com/author/jon' );
|
|
$this->assertEquals( 'https://example.com/author/jon', $follower2->get_url() );
|
|
|
|
\Activitypub\Collection\Followers::remove_follower( 1, 'https://example.com/author/jon' );
|
|
|
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
|
$this->assertNull( $follower );
|
|
|
|
$follower2 = \Activitypub\Collection\Followers::get_follower( 2, 'https://example.com/author/jon' );
|
|
$this->assertEquals( 'https://example.com/author/jon', $follower2->get_url() );
|
|
|
|
$followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
|
$this->assertEquals( 1, count( $followers ) );
|
|
}
|
|
|
|
public function test_get_outdated_followers() {
|
|
$followers = array( 'https://example.com/author/jon', 'https://example.org/author/doe', 'http://sally.example.org' );
|
|
|
|
$pre_http_request = new MockAction();
|
|
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
|
|
|
|
foreach ( $followers as $follower ) {
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
}
|
|
|
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
|
|
|
global $wpdb;
|
|
|
|
//eg. time one year ago..
|
|
$time = time() - 804800;
|
|
$mysql_time_format = 'Y-m-d H:i:s';
|
|
|
|
$post_modified = gmdate( $mysql_time_format, $time );
|
|
$post_modified_gmt = gmdate( $mysql_time_format, ( $time + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
|
|
$post_id = $follower->get__id();
|
|
|
|
$wpdb->query(
|
|
$wpdb->prepare(
|
|
"UPDATE $wpdb->posts SET post_modified = %s, post_modified_gmt = %s WHERE ID = %s",
|
|
array(
|
|
$post_modified,
|
|
$post_modified_gmt,
|
|
$post_id,
|
|
)
|
|
)
|
|
);
|
|
|
|
clean_post_cache( $post_id );
|
|
|
|
$followers = \Activitypub\Collection\Followers::get_outdated_followers();
|
|
$this->assertEquals( 1, count( $followers ) );
|
|
$this->assertEquals( 'https://example.com/author/jon', $followers[0] );
|
|
}
|
|
|
|
public function test_get_faulty_followers() {
|
|
$followers = array( 'https://example.com/author/jon', 'https://example.org/author/doe', 'http://sally.example.org' );
|
|
|
|
$pre_http_request = new MockAction();
|
|
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
|
|
|
|
foreach ( $followers as $follower ) {
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
}
|
|
|
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'http://sally.example.org' );
|
|
|
|
for ( $i = 1; $i <= 15; $i++ ) {
|
|
add_post_meta( $follower->get__id(), 'activitypub_errors', 'error ' . $i );
|
|
}
|
|
|
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'http://sally.example.org' );
|
|
$count = $follower->count_errors();
|
|
|
|
$followers = \Activitypub\Collection\Followers::get_faulty_followers();
|
|
|
|
$this->assertEquals( 1, count( $followers ) );
|
|
$this->assertEquals( 'http://sally.example.org', $followers[0] );
|
|
|
|
$follower->reset_errors();
|
|
|
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'http://sally.example.org' );
|
|
$count = $follower->count_errors();
|
|
|
|
$followers = \Activitypub\Collection\Followers::get_faulty_followers();
|
|
|
|
$this->assertEquals( 0, count( $followers ) );
|
|
}
|
|
|
|
public function test_add_duplicate_follower() {
|
|
$pre_http_request = new MockAction();
|
|
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
|
|
|
|
$follower = 'https://12345.example.com';
|
|
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
|
|
|
$db_followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
|
|
|
$this->assertContains( $follower, $db_followers );
|
|
|
|
$follower = current( $db_followers );
|
|
$meta = get_post_meta( $follower->get__id(), 'activitypub_user_id' );
|
|
|
|
$this->assertCount( 1, $meta );
|
|
}
|
|
|
|
public function test_migration() {
|
|
$pre_http_request = new MockAction();
|
|
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
|
|
|
|
$followers = array(
|
|
'https://example.com/author/jon',
|
|
'https://example.og/errors',
|
|
'https://example.org/author/doe',
|
|
'http://sally.example.org',
|
|
'https://error.example.com',
|
|
'https://example.net/error',
|
|
);
|
|
|
|
$user_id = 1;
|
|
|
|
add_user_meta( $user_id, 'activitypub_followers', $followers, true );
|
|
|
|
\Activitypub\Migration::maybe_migrate();
|
|
|
|
$db_followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
|
|
|
$this->assertCount( 3, $db_followers );
|
|
}
|
|
|
|
/**
|
|
* @dataProvider extract_name_from_uri_content_provider
|
|
*/
|
|
public function test_extract_name_from_uri( $uri, $name ) {
|
|
$follower = new \Activitypub\Model\Follower();
|
|
|
|
$follower->set_id( $uri );
|
|
|
|
$this->assertEquals( $name, $follower->get_name() );
|
|
}
|
|
|
|
public static function http_request_host_is_external( $in, $host ) {
|
|
if ( in_array( $host, array( 'example.com', 'example.org' ), true ) ) {
|
|
return true;
|
|
}
|
|
return $in;
|
|
}
|
|
|
|
public static function http_request_args( $args, $url ) {
|
|
if ( in_array( wp_parse_url( $url, PHP_URL_HOST ), array( 'example.com', 'example.org' ), true ) ) {
|
|
$args['reject_unsafe_urls'] = false;
|
|
}
|
|
return $args;
|
|
}
|
|
|
|
public static function pre_http_request( $preempt, $request, $url ) {
|
|
return array(
|
|
'headers' => array(
|
|
'content-type' => 'text/json',
|
|
),
|
|
'body' => '',
|
|
'response' => array(
|
|
'code' => 202,
|
|
),
|
|
);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
public function extract_name_from_uri_content_provider() {
|
|
return array(
|
|
array( 'https://example.com/@user', 'user' ),
|
|
array( 'https://example.com/@user/', 'user' ),
|
|
array( 'https://example.com/users/user', 'user' ),
|
|
array( 'https://example.com/users/user/', 'user' ),
|
|
array( 'https://example.com/@user?as=asasas', 'user' ),
|
|
array( 'https://example.com/@user#asass', 'user' ),
|
|
array( '@user@example.com', 'user' ),
|
|
array( 'acct:user@example.com', 'user' ),
|
|
array( 'user@example.com', 'user' ),
|
|
array( 'https://example.com', 'https://example.com' ),
|
|
);
|
|
}
|
|
}
|