Add ActivityPub mentions
This commit is contained in:
parent
be369b11e5
commit
e065880085
12 changed files with 273 additions and 27 deletions
|
@ -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();
|
||||||
|
|
||||||
|
|
63
includes/class-mention.php
Normal file
63
includes/class-mention.php
Normal 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;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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',
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
22
tests/fixtures/notiz-blog-author-matthias-pfefferle.json
vendored
Normal file
22
tests/fixtures/notiz-blog-author-matthias-pfefferle.json
vendored
Normal 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
|
||||||
|
}
|
||||||
|
}
|
22
tests/fixtures/notiz-blog-well-known-webfinger.json
vendored
Normal file
22
tests/fixtures/notiz-blog-well-known-webfinger.json
vendored
Normal 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
|
||||||
|
}
|
||||||
|
}
|
34
tests/test-class-activitypub-mention.php
Normal file
34
tests/test-class-activitypub-mention.php
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
7
tests/test-functions.php
Normal 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 );
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue