Add ActivityPub mentions

This commit is contained in:
Alex Kirk 2022-12-09 11:59:24 +01:00
parent be369b11e5
commit e065880085
12 changed files with 273 additions and 27 deletions

View file

@ -22,6 +22,8 @@ function init() {
\defined( 'ACTIVITYPUB_EXCERPT_LENGTH' ) || \define( 'ACTIVITYPUB_EXCERPT_LENGTH', 400 ); \defined( 'ACTIVITYPUB_EXCERPT_LENGTH' ) || \define( 'ACTIVITYPUB_EXCERPT_LENGTH', 400 );
\defined( 'ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS' ) || \define( 'ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS', 3 ); \defined( 'ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS' ) || \define( 'ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS', 3 );
\defined( 'ACTIVITYPUB_HASHTAGS_REGEXP' ) || \define( 'ACTIVITYPUB_HASHTAGS_REGEXP', '(?:(?<=\s)|(?<=<p>)|(?<=<br>)|^)#([A-Za-z0-9_]+)(?:(?=\s|[[:punct:]]|$))' ); \defined( 'ACTIVITYPUB_HASHTAGS_REGEXP' ) || \define( 'ACTIVITYPUB_HASHTAGS_REGEXP', '(?:(?<=\s)|(?<=<p>)|(?<=<br>)|^)#([A-Za-z0-9_]+)(?:(?=\s|[[:punct:]]|$))' );
\defined( 'ACTIVITYPUB_USERNAME_REGEXP' ) || \define( 'ACTIVITYPUB_USERNAME_REGEXP', '(?:[^@]+@((?:[A-Za-z0-9_-]+\.)+[A-Za-z]+))' );
\defined( 'ACTIVITYPUB_ALLOWED_HTML' ) || \define( 'ACTIVITYPUB_ALLOWED_HTML', '<strong><a><p><ul><ol><li><code><blockquote><pre><img>' );
\defined( 'ACTIVITYPUB_CUSTOM_POST_CONTENT' ) || \define( 'ACTIVITYPUB_CUSTOM_POST_CONTENT', "<p><strong>[ap_title]</strong></p>\n\n[ap_content]\n\n<p>[ap_hashtags]</p>\n\n<p>[ap_shortlink]</p>" ); \defined( 'ACTIVITYPUB_CUSTOM_POST_CONTENT' ) || \define( 'ACTIVITYPUB_CUSTOM_POST_CONTENT', "<p><strong>[ap_title]</strong></p>\n\n[ap_content]\n\n<p>[ap_hashtags]</p>\n\n<p>[ap_shortlink]</p>" );
\define( 'ACTIVITYPUB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); \define( 'ACTIVITYPUB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
\define( 'ACTIVITYPUB_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); \define( 'ACTIVITYPUB_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
@ -73,6 +75,9 @@ function init() {
require_once \dirname( __FILE__ ) . '/includes/class-shortcodes.php'; require_once \dirname( __FILE__ ) . '/includes/class-shortcodes.php';
\Activitypub\Shortcodes::init(); \Activitypub\Shortcodes::init();
require_once \dirname( __FILE__ ) . '/includes/class-mention.php';
\Activitypub\Mention::init();
require_once \dirname( __FILE__ ) . '/includes/class-debug.php'; require_once \dirname( __FILE__ ) . '/includes/class-debug.php';
\Activitypub\Debug::init(); \Activitypub\Debug::init();

View file

@ -0,0 +1,63 @@
<?php
namespace Activitypub;
/**
* ActivityPub Mention Class
*
* @author Alex Kirk
*/
class Mention {
/**
* Initialize the class, registering WordPress hooks
*/
public static function init() {
\add_filter( 'the_content', array( '\Activitypub\Mention', 'the_content' ), 99, 2 );
\add_filter( 'activitypub_extract_mentions', array( '\Activitypub\Mention', 'extract_mentions' ), 99, 2 );
}
/**
* Filter to replace the #tags in the content with links
*
* @param string $the_content the post-content
*
* @return string the filtered post-content
*/
public static function the_content( $the_content ) {
$the_content = \preg_replace_callback( '/@' . ACTIVITYPUB_USERNAME_REGEXP . '/i', array( '\Activitypub\Mention', 'replace_with_links' ), $the_content );
return $the_content;
}
/**
* A callback for preg_replace to build the term links
*
* @param array $result the preg_match results
* @return string the final string
*/
public static function replace_with_links( $result ) {
$metadata = \ActivityPub\get_remote_metadata_by_actor( $result[0] );
if ( ! is_wp_error( $metadata ) ) {
$username = $metadata['name'];
if ( ! empty( $metadata['preferredUsername'] ) ) {
$username = $metadata['preferredUsername'];
}
$username = '@<span>' . $username . '</span>';
return \sprintf( '<a rel="mention" class="u-url mention href="%s">%s</a>', $metadata['url'], $username );
}
return $username;
}
public static function extract_mentions( $mentions, \ActivityPub\Model\Post $post ) {
\preg_match_all( '/@' . ACTIVITYPUB_USERNAME_REGEXP . '/i', $post->get_content(), $matches );
foreach ( $matches[0] as $match ) {
$link = \Activitypub\Rest\Webfinger::resolve( $match );
if ( ! is_wp_error( $link ) ) {
$mentions[ $match ] = $link;
}
}
return $mentions;
}
}

View file

@ -110,8 +110,8 @@ function get_remote_metadata_by_actor( $actor ) {
if ( $pre ) { if ( $pre ) {
return $pre; return $pre;
} }
if ( preg_match( '/^@?[^@]+@((?:[a-z0-9-]+\.)+[a-z]+)$/i', $actor ) ) { if ( preg_match( '/^@?' . ACTIVITYPUB_USERNAME_REGEXP . '$/i', $actor ) ) {
$actor = \Activitypub\Webfinger::resolve( $actor ); $actor = Rest\Webfinger::resolve( $actor );
} }
if ( ! $actor ) { if ( ! $actor ) {
@ -135,7 +135,7 @@ function get_remote_metadata_by_actor( $actor ) {
$user = \get_users( $user = \get_users(
array( array(
'number' => 1, 'number' => 1,
'who' => 'authors', 'capability__in' => array( 'publish_posts' ),
'fields' => 'ID', 'fields' => 'ID',
) )
); );

View file

@ -46,8 +46,7 @@ class Activity {
} }
public function from_post( Post $post ) { public function from_post( Post $post ) {
$object = apply_filters( 'activitypub_from_post_array', $post->to_array() ); $this->object = $post->to_array();
$this->object = $object;
if ( isset( $object['published'] ) ) { if ( isset( $object['published'] ) ) {
$this->published = $object['published']; $this->published = $object['published'];
@ -58,9 +57,10 @@ class Activity {
$this->actor = $object['attributedTo']; $this->actor = $object['attributedTo'];
} }
$mentions = apply_filters( 'activitypub_extract_mentions', array(), $post ); foreach ( $post->get_tags() as $tag ) {
foreach ( $mentions as $mention ) { if ( 'Mention' === $tag['type'] ) {
$this->cc[] = $mention; $this->cc[] = $tag['href'];
}
} }
$type = \strtolower( $this->type ); $type = \strtolower( $this->type );

View file

@ -278,6 +278,18 @@ class Post {
} }
} }
$mentions = apply_filters( 'activitypub_extract_mentions', array(), $this );
if ( $mentions ) {
foreach ( $mentions as $mention => $url ) {
$tag = array(
'type' => 'Mention',
'href' => $url,
'name' => $mention,
);
$tags[] = $tag;
}
}
$this->tags = $tags; $this->tags = $tags;
return $tags; return $tags;

View file

@ -118,4 +118,47 @@ class Webfinger {
return $array; return $array;
} }
public static function resolve( $account ) {
if ( ! preg_match( '/^@?' . ACTIVITYPUB_USERNAME_REGEXP . '$/i', $account, $m ) ) {
return null;
}
$url = \add_query_arg( 'resource', 'acct:' . ltrim( $account, '@' ), 'https://' . $m[1] . '/.well-known/webfinger' );
if ( ! \wp_http_validate_url( $url ) ) {
echo $url;
exit;
return new \WP_Error( 'invalid_webfinger_url', null, $url );
}
// try to access author URL
$response = \wp_remote_get(
$url,
array(
'headers' => array( 'Accept' => 'application/activity+json' ),
'redirection' => 0,
)
);
if ( \is_wp_error( $response ) ) {
return new \WP_Error( 'webfinger_url_not_accessible', null, $url );
}
$response_code = \wp_remote_retrieve_response_code( $response );
$body = \wp_remote_retrieve_body( $response );
$body = \json_decode( $body, true );
if ( ! isset( $body['links'] ) ) {
return new \WP_Error( 'webfinger_url_invalid_response', null, $url );
}
foreach ( $body['links'] as $link ) {
if ( 'self' === $link['rel'] && 'application/activity+json' === $link['type'] ) {
return $link['href'];
}
}
return new \WP_Error( 'webfinger_url_no_activity_pub', null, $body );
}
} }

View file

@ -29,6 +29,8 @@ class Friends_Feed_Parser_ActivityPub extends \Friends\Feed_Parser {
\add_action( 'friends_feed_parser_activitypub_follow', array( $this, 'follow_user' ), 10, 2 ); \add_action( 'friends_feed_parser_activitypub_follow', array( $this, 'follow_user' ), 10, 2 );
\add_action( 'friends_feed_parser_activitypub_unfollow', array( $this, 'unfollow_user' ), 10, 2 ); \add_action( 'friends_feed_parser_activitypub_unfollow', array( $this, 'unfollow_user' ), 10, 2 );
\add_filter( 'friends_rewrite_incoming_url', array( $this, 'friends_rewrite_incoming_url' ), 10, 2 ); \add_filter( 'friends_rewrite_incoming_url', array( $this, 'friends_rewrite_incoming_url' ), 10, 2 );
\add_filter( 'activitypub_extract_mentions', array( $this, 'activitypub_extract_mentions' ), 10, 2 );
} }
/** /**
@ -94,8 +96,8 @@ class Friends_Feed_Parser_ActivityPub extends \Friends\Feed_Parser {
* @return <type> ( description_of_the_return_value ) * @return <type> ( description_of_the_return_value )
*/ */
public function friends_rewrite_incoming_url( $url, $incoming_url ) { public function friends_rewrite_incoming_url( $url, $incoming_url ) {
if ( preg_match( '/^@?[^@]+@((?:[a-z0-9-]+\.)+[a-z]+)$/i', $incoming_url ) ) { if ( preg_match( '/^@?' . ACTIVITYPUB_USERNAME_REGEXP . '$/i', $incoming_url ) ) {
$resolved_url = \Activitypub\Webfinger::resolve( $incoming_url ); $resolved_url = \Activitypub\Rest\Webfinger::resolve( $incoming_url );
if ( ! is_wp_error( $resolved_url ) ) { if ( ! is_wp_error( $resolved_url ) ) {
return $resolved_url; return $resolved_url;
} }
@ -124,6 +126,7 @@ class Friends_Feed_Parser_ActivityPub extends \Friends\Feed_Parser {
'autoselect' => true, 'autoselect' => true,
); );
} }
return $discovered_feeds; return $discovered_feeds;
} }
@ -406,4 +409,21 @@ class Friends_Feed_Parser_ActivityPub extends \Friends\Feed_Parser {
$activity = $activity->to_json(); $activity = $activity->to_json();
\Activitypub\safe_remote_post( $inbox, $activity, $user_id ); \Activitypub\safe_remote_post( $inbox, $activity, $user_id );
} }
public function activitypub_extract_mentions( $mentions, \ActivityPub\Model\Post $post ) {
$feeds = \Friends\User_Feed::get_by_parser( 'activitypub' );
$users = array();
foreach ( $feeds as $feed ) {
$user = $feed->get_friend_user();
$slug = sanitize_title( $user->user_nicename );
$users[ '@' . $slug ] = $feed->get_url();
}
preg_match_all( '/@(?:[a-zA-Z0-9_-]+)/', $post->get_content(), $matches );
foreach ( $matches[0] as $match ) {
if ( isset( $users[ $match ] ) ) {
$mentions[ $match ] = $users[ $match ];
}
}
return $mentions;
}
} }

View file

@ -0,0 +1,22 @@
{
"headers": {
"date": "Fri, 09 Dec 2022 10:39:51 GMT",
"content-type": "application\/activity+json",
"server": "nginx",
"x-xrds-location": "https:\/\/notiz.blog\/?xrds",
"x-yadis-location": "https:\/\/notiz.blog\/?xrds",
"link": "<https:\/\/notiz.blog\/wp-api\/micropub\/1.0\/media>; rel=\"micropub_media\", <https:\/\/notiz.blog\/wp-api\/micropub\/1.0\/endpoint>; rel=\"micropub\", <https:\/\/notiz.blog\/wp-api\/friends\/v1>; rel=\"friends-base-url\", <https:\/\/notiz.blog\/wp-api\/indieauth\/1.0\/auth>; rel=\"authorization_endpoint\", <https:\/\/notiz.blog\/wp-api\/indieauth\/1.0\/token>; rel=\"token_endpoint\", <https:\/\/notiz.blog\/wp-api\/indieauth\/1.0\/metadata>; rel=\"indieauth-metadata\", <https:\/\/notiz.blog\/wp-api\/>; rel=\"https:\/\/api.w.org\/\", <https:\/\/notiz.blog\/wp-api\/wp\/v2\/users\/1>; rel=\"alternate\"; type=\"application\/json\"",
"cache-control": "max-age=0, public",
"expires": "Fri, 09 Dec 2022 10:39:51 GMT",
"x-xss-protection": "1; mode=block",
"x-content-type-options": "nosniff",
"strict-transport-security": "max-age=31536000",
"x-frame-options": "SAMEORIGIN",
"referrer-policy": "strict-origin-when-cross-origin",
"x-clacks-overhead": "GNU Terry Pratchett"
},
"body": "{\"@context\":[\"https:\\\/\\\/www.w3.org\\\/ns\\\/activitystreams\",\"https:\\\/\\\/w3id.org\\\/security\\\/v1\",{\"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\":{\"@id\":\"toot:featured\",\"@type\":\"@id\"},\"featuredTags\":{\"@id\":\"toot:featuredTags\",\"@type\":\"@id\"}}],\"id\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/\",\"type\":\"Person\",\"name\":\"Matthias Pfefferle\",\"summary\":\"Ich bin Webworker und arbeite als \\u0022Head of WordPress Development\\u0022 f\\u00fcr IONOS in Karlsruhe. Ich blogge, podcaste und schreibe \\u003Cdel\\u003Eeine Kolumne\\u003C\\\/del\\u003E \\u00fcber das open, independent und federated social Web. \\u003Ca href=\\u0022https:\\\/\\\/notiz.blog\\\/about\\\/\\u0022\\u003EMehr \\u00fcber mich.\\u003C\\\/a\\u003E\",\"preferredUsername\":\"pfefferle\",\"url\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/\",\"icon\":{\"type\":\"Image\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/75512bb584bbceae57dfc503692b16b2?s=120\\u0026d=mm\\u0026r=g\"},\"image\":{\"type\":\"Image\",\"url\":\"https:\\\/\\\/notiz.blog\\\/wp-content\\\/uploads\\\/2017\\\/02\\\/cropped-Unknown-2.jpeg\"},\"inbox\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/activitypub\\\/1.0\\\/users\\\/1\\\/inbox\",\"outbox\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/activitypub\\\/1.0\\\/users\\\/1\\\/outbox\",\"followers\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/activitypub\\\/1.0\\\/users\\\/1\\\/followers\",\"following\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/activitypub\\\/1.0\\\/users\\\/1\\\/following\",\"manuallyApprovesFollowers\":false,\"publicKey\":{\"id\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/#main-key\",\"owner\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/\",\"publicKeyPem\":\"-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA039CnlArzn6nsRjcC2RJ\\nrjY3K5ZrLnFUbPtHLGNXMJUGW+rFYE1DzhdKPTj9giiXE+J7ADI0Tme5rSWw14bT\\nLhOMBs2ma8d03\\\/wnF1+kxDBeRyvyoki2TjtiJdoPu1jwZLLYTuzWTXdDiqrwSKOL\\nncKFGIkjyzOLoYuIKPgIuFg3Mt8rI6teQ2Q65YsGvOG\\\/mjBOUwl5FjgcGt9aQARd\\nmFxW5XydxfNrCZwuE34Zbq\\\/IC7rvaUx98zvrEHrD237YQ8O4M3afC9Kbu5Xp7k8Q\\n5JG80RItV7n8xjyt0i9LaVwlZDDYmLDYv50VhjcwRvtVFVfaN7yxDnHttd1NNENK\\nCwIDAQAB\\n-----END PUBLIC KEY-----\"},\"tag\":[],\"attachment\":[{\"type\":\"PropertyValue\",\"name\":\"Blog\",\"value\":\"\\u003Ca rel=\\u0022me\\u0022 title=\\u0022https:\\\/\\\/notiz.blog\\\/\\u0022 target=\\u0022_blank\\u0022 href=\\u0022https:\\\/\\\/notiz.blog\\\/\\u0022\\u003Enotiz.blog\\u003C\\\/a\\u003E\"},{\"type\":\"PropertyValue\",\"name\":\"Profil\",\"value\":\"\\u003Ca rel=\\u0022me\\u0022 title=\\u0022https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/\\u0022 target=\\u0022_blank\\u0022 href=\\u0022https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/\\u0022\\u003Enotiz.blog\\u003C\\\/a\\u003E\"},{\"type\":\"PropertyValue\",\"name\":\"Website\",\"value\":\"\\u003Ca rel=\\u0022me\\u0022 title=\\u0022https:\\\/\\\/pfefferle.org\\\/\\u0022 target=\\u0022_blank\\u0022 href=\\u0022https:\\\/\\\/pfefferle.org\\\/\\u0022\\u003Epfefferle.org\\u003C\\\/a\\u003E\"}]}",
"response": {
"code": 200
}
}

View file

@ -0,0 +1,22 @@
{
"headers": {
"date": "Fri, 09 Dec 2022 10:39:51 GMT",
"content-type": "application\/jrd+json; charset=UTF-8",
"server": "nginx",
"x-xrds-location": "https:\/\/notiz.blog\/?xrds",
"x-yadis-location": "https:\/\/notiz.blog\/?xrds",
"access-control-allow-origin": "*",
"cache-control": "max-age=2592000, public",
"expires": "Sun, 08 Jan 2023 10:39:50 GMT",
"x-xss-protection": "1; mode=block",
"x-content-type-options": "nosniff",
"strict-transport-security": "max-age=31536000",
"x-frame-options": "SAMEORIGIN",
"referrer-policy": "strict-origin-when-cross-origin",
"x-clacks-overhead": "GNU Terry Pratchett"
},
"body": "{\"subject\":\"acct:pfefferle@notiz.blog\",\"aliases\":[\"acct:pfefferle@notiz.blog\",\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/\",\"mailto:pfefferle@notiz.blog\"],\"links\":[{\"rel\":\"http:\\\/\\\/webfinger.net\\\/rel\\\/profile-page\",\"href\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/\",\"type\":\"text\\\/html\"},{\"rel\":\"http:\\\/\\\/webfinger.net\\\/rel\\\/avatar\",\"href\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/75512bb584bbceae57dfc503692b16b2?s=96&d=mm&r=g\"},{\"rel\":\"http:\\\/\\\/webfinger.net\\\/rel\\\/profile-page\",\"href\":\"https:\\\/\\\/pfefferle.org\\\/\",\"type\":\"text\\\/html\"},{\"rel\":\"payment\",\"href\":\"https:\\\/\\\/www.paypal.me\\\/matthiaspfefferle\"},{\"rel\":\"payment\",\"href\":\"https:\\\/\\\/liberapay.com\\\/pfefferle\\\/\"},{\"rel\":\"payment\",\"href\":\"https:\\\/\\\/notiz.blog\\\/donate\\\/\"},{\"rel\":\"payment\",\"href\":\"https:\\\/\\\/flattr.com\\\/@pfefferle\"},{\"href\":\"https:\\\/\\\/notiz.blog\\\/\",\"rel\":\"http:\\\/\\\/specs.openid.net\\\/auth\\\/2.0\\\/provider\"},{\"rel\":\"self\",\"type\":\"application\\\/activity+json\",\"href\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/\"},{\"rel\":\"micropub_media\",\"href\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/micropub\\\/1.0\\\/media\"},{\"rel\":\"micropub\",\"href\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/micropub\\\/1.0\\\/endpoint\"},{\"rel\":\"http:\\\/\\\/nodeinfo.diaspora.software\\\/ns\\\/schema\\\/2.0\",\"href\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/nodeinfo\\\/2.0\"},{\"rel\":\"http:\\\/\\\/nodeinfo.diaspora.software\\\/ns\\\/schema\\\/1.1\",\"href\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/nodeinfo\\\/1.1\"},{\"rel\":\"http:\\\/\\\/nodeinfo.diaspora.software\\\/ns\\\/schema\\\/1.0\",\"href\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/nodeinfo\\\/1.0\"},{\"rel\":\"https:\\\/\\\/feneas.org\\\/ns\\\/serviceinfo\",\"type\":\"application\\\/ld+json\",\"href\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/serviceinfo\\\/1.0\",\"properties\":{\"https:\\\/\\\/feneas.org\\\/ns\\\/serviceinfo#software.name\":\"notizBlog\"}},{\"rel\":\"http:\\\/\\\/schemas.google.com\\\/g\\\/2010#updates-from\",\"href\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/feed\\\/ostatus\\\/\",\"type\":\"application\\\/atom+xml\"},{\"rel\":\"http:\\\/\\\/ostatus.org\\\/schema\\\/1.0\\\/subscribe\",\"template\":\"https:\\\/\\\/notiz.blog\\\/?profile={uri}\"},{\"rel\":\"magic-public-key\",\"href\":\"data:application\\\/magic-public-key,RSA.039CnlArzn6nsRjcC2RJrjY3K5ZrLnFUbPtHLGNXMJUGW-rFYE1DzhdKPTj9giiXE-J7ADI0Tme5rSWw14bTLhOMBs2ma8d03_wnF1-kxDBeRyvyoki2TjtiJdoPu1jwZLLYTuzWTXdDiqrwSKOLncKFGIkjyzOLoYuIKPgIuFg3Mt8rI6teQ2Q65YsGvOG_mjBOUwl5FjgcGt9aQARdmFxW5XydxfNrCZwuE34Zbq_IC7rvaUx98zvrEHrD237YQ8O4M3afC9Kbu5Xp7k8Q5JG80RItV7n8xjyt0i9LaVwlZDDYmLDYv50VhjcwRvtVFVfaN7yxDnHttd1NNENKCw==.AQAB\"},{\"rel\":\"salmon\",\"href\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/?salmon=endpoint\"},{\"rel\":\"http:\\\/\\\/salmon-protocol.org\\\/ns\\\/salmon-replies\",\"href\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/?salmon=endpoint\"},{\"rel\":\"http:\\\/\\\/salmon-protocol.org\\\/ns\\\/salmon-mention\",\"href\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/?salmon=endpoint\"},{\"rel\":\"feed\",\"type\":\"application\\\/stream+json\",\"title\":\"Activity-Streams 1.0 Feed\",\"href\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/feed\\\/as1\\\/\"},{\"rel\":\"feed\",\"type\":\"application\\\/activity+json\",\"title\":\"Activity-Streams 2.0 Feed\",\"href\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/feed\\\/as2\\\/\"},{\"rel\":\"http:\\\/\\\/oexchange.org\\\/spec\\\/0.8\\\/rel\\\/user-target\",\"href\":\"https:\\\/\\\/notiz.blog\\\/?oexchange=xrd\",\"type\":\"application\\\/xrd+xml\"},{\"rel\":\"http:\\\/\\\/a9.com\\\/-\\\/spec\\\/opensearch\\\/1.1\\\/\",\"href\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/opensearch\\\/1.1\\\/document\",\"type\":\"application\\\/opensearchdescription+xml\"},{\"rel\":\"describedby\",\"href\":\"https:\\\/\\\/notiz.blog\\\/author\\\/matthias-pfefferle\\\/feed\\\/foaf\\\/\",\"type\":\"application\\\/rdf+xml\"},{\"rel\":\"webmention\",\"href\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/webmention\\\/1.0\\\/endpoint\"},{\"rel\":\"http:\\\/\\\/webmention.org\\\/\",\"href\":\"https:\\\/\\\/notiz.blog\\\/wp-api\\\/webmention\\\/1.0\\\/endpoint\"}],\"properties\":{\"http:\\\/\\\/salmon-protocol.org\\\/ns\\\/magic-key\":\"RSA.039CnlArzn6nsRjcC2RJrjY3K5ZrLnFUbPtHLGNXMJUGW-rFYE1DzhdKPTj9giiXE-J7ADI0Tme5rSWw14bTLhOMBs2ma8d03_wnF1-kxDBeRyvyoki2TjtiJdoPu1jwZLLYTuzWTXdDiqrwSKOLncKFGIkjyzOLoYuIKPgIuFg3Mt8rI6teQ2Q65YsGvOG_mjBOUwl5FjgcGt9aQARdmFxW5XydxfNrCZwuE34Zbq_IC7rvaUx98zvrEHrD237YQ8O4M3afC9Kbu5Xp7k8Q5JG80RItV7n8xjyt0i9LaVwlZDDYmLDYv50VhjcwRvtVFVfaN7yxDnHttd1NNENKCw==.AQAB\"}}",
"response": {
"code": 200
}
}

View file

@ -0,0 +1,34 @@
<?php
class Test_Activitypub_Mention extends ActivityPub_TestCase_Cache_HTTP {
public static $users = array(
'username@example.org' => array(
'url' => 'https://example.org/users/username',
'name' => 'username',
),
);
/**
* @dataProvider the_content_provider
*/
public function test_the_content( $content, $content_with_mention ) {
add_filter( 'pre_get_remote_metadata_by_actor', array( get_called_class(), 'pre_get_remote_metadata_by_actor' ), 10, 2 );
$content = \Activitypub\Mention::the_content( $content );
remove_filter( 'pre_get_remote_metadata_by_actor', array( get_called_class(), 'pre_get_remote_metadata_by_actor' ) );
$this->assertEquals( $content_with_mention, $content );
}
public function the_content_provider() {
return array(
array( 'hallo @username@example.org test', 'hallo <a rel="mention" class="u-url mention href="https://example.org/users/username">@<span>username</span></a> test' ),
array( 'hallo @pfefferle@notiz.blog test', 'hallo <a rel="mention" class="u-url mention href="https://notiz.blog/author/matthias-pfefferle/">@<span>pfefferle</span></a> test' ),
);
}
public static function pre_get_remote_metadata_by_actor( $pre, $actor ) {
$actor = ltrim( $actor, '@' );
if ( isset( self::$users[ $actor ] ) ) {
return self::$users[ $actor ];
}
return $pre;
}
}

View file

@ -161,29 +161,43 @@ class Test_Friends_Feed_Parser_ActivityPub extends ActivityPub_TestCase_Cache_HT
$this->assertEquals( 'Matthias Pfefferle', get_post_meta( $posts[0]->ID, 'author', true ) ); $this->assertEquals( 'Matthias Pfefferle', get_post_meta( $posts[0]->ID, 'author', true ) );
} }
public function test_friend_mentions() {
$post = \wp_insert_post(
array(
'post_author' => 1,
'post_content' => '@' . sanitize_title( $this->friend_nicename ) . ' hello',
)
);
$activitypub_post = new \Activitypub\Model\Post( $post );
$activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL );
$activitypub_activity->from_post( $activitypub_post );
$this->assertContains(
array(
'type' => 'Mention',
'href' => $this->actor,
'name' => '@' . $this->friend_nicename,
),
$activitypub_post->get_tags()
);
$this->assertContains( \get_rest_url( null, '/activitypub/1.0/users/1/followers' ), $activitypub_activity->get_cc() );
$this->assertContains( $this->actor, $activitypub_activity->get_cc() );
remove_all_filters( 'activitypub_from_post_object' );
\wp_trash_post( $post );
}
public function set_up() { public function set_up() {
if ( ! class_exists( '\Friends\Friends' ) ) { if ( ! class_exists( '\Friends\Friends' ) ) {
return $this->markTestSkipped( 'The Friends plugin is not loaded.' ); return $this->markTestSkipped( 'The Friends plugin is not loaded.' );
} }
parent::set_up(); parent::set_up();
// Manually activate the REST server.
global $wp_rest_server;
$wp_rest_server = new \Spy_REST_Server();
$this->server = $wp_rest_server;
do_action( 'rest_api_init' );
add_filter(
'rest_url',
function() {
return get_option( 'home' ) . '/wp-json/';
}
);
add_filter( 'pre_http_request', array( get_called_class(), 'pre_http_request' ), 10, 3 );
add_filter( 'http_response', array( get_called_class(), 'http_response' ), 10, 3 );
add_filter( 'http_request_host_is_external', array( get_called_class(), 'http_request_host_is_external' ), 10, 2 );
add_filter( 'http_request_args', array( get_called_class(), 'http_request_args' ), 10, 2 );
add_filter( 'pre_get_remote_metadata_by_actor', array( get_called_class(), 'pre_get_remote_metadata_by_actor' ), 10, 2 ); add_filter( 'pre_get_remote_metadata_by_actor', array( get_called_class(), 'pre_get_remote_metadata_by_actor' ), 10, 2 );
$user_id = $this->factory->user->create( $user_id = $this->factory->user->create(
@ -200,7 +214,9 @@ class Test_Friends_Feed_Parser_ActivityPub extends ActivityPub_TestCase_Cache_HT
if ( is_wp_error( $user_feed ) ) { if ( is_wp_error( $user_feed ) ) {
$this->friend_id = $this->factory->user->create( $this->friend_id = $this->factory->user->create(
array( array(
'user_login' => 'akirk.blog',
'display_name' => $this->friend_name, 'display_name' => $this->friend_name,
'nicename' => $this->friend_nicename,
'role' => 'friend', 'role' => 'friend',
) )
); );
@ -214,6 +230,8 @@ class Test_Friends_Feed_Parser_ActivityPub extends ActivityPub_TestCase_Cache_HT
} else { } else {
$this->friend_id = $user_feed->get_friend_user()->ID; $this->friend_id = $user_feed->get_friend_user()->ID;
} }
$userdata = get_userdata( $this->friend_id );
$this->friend_nicename = $userdata->user_nicename;
self::$users[ $this->actor ] = array( self::$users[ $this->actor ] = array(
'url' => $this->actor, 'url' => $this->actor,

7
tests/test-functions.php Normal file
View file

@ -0,0 +1,7 @@
<?php
class Test_Functions extends ActivityPub_TestCase_Cache_HTTP {
public function test_get_remote_metadata_by_actor() {
$metadata = \ActivityPub\get_remote_metadata_by_actor( 'pfefferle@notiz.blog' );
$this->assertArrayHasKey( 'url', $metadata );
}
}