Merge branch 'master' into fix/sanitization
This commit is contained in:
commit
27dd8217e8
29 changed files with 826 additions and 213 deletions
11
README.md
11
README.md
|
@ -20,11 +20,12 @@ The plugin works with the following tested federated platforms, but there may be
|
|||
|
||||
* [Mastodon](https://joinmastodon.org/)
|
||||
* [Pleroma](https://pleroma.social/)
|
||||
* [Friendica](https://friendi.ca/)
|
||||
* [HubZilla](https://hubzilla.org/)
|
||||
* [friendica](https://friendi.ca/)
|
||||
* [Hubzilla](https://hubzilla.org/)
|
||||
* [Pixelfed](https://pixelfed.org/)
|
||||
* [SocialHome](https://socialhome.network/)
|
||||
* [Socialhome](https://socialhome.network/)
|
||||
* [Misskey](https://join.misskey.page/)
|
||||
* [Calckey](https://calckey.org/)
|
||||
|
||||
Here’s what that means and what you can expect.
|
||||
|
||||
|
@ -94,7 +95,7 @@ In order for webfinger to work, it must be mapped to the root directory of the U
|
|||
|
||||
Add the following to the .htaccess file in the root directory:
|
||||
|
||||
RedirectMatch "^\/\.well-known(.*)$" "\/blog\/\.well-known$1"
|
||||
RedirectMatch "^\/\.well-known/(webfinger|nodeinfo|x-nodeinfo2)(.*)$" "\/blog\/\.well-known$1$2"
|
||||
|
||||
Where 'blog' is the path to the subdirectory at which your blog resides.
|
||||
|
||||
|
@ -115,6 +116,8 @@ Project maintained on GitHub at [automattic/wordpress-activitypub](https://githu
|
|||
|
||||
### Next ###
|
||||
|
||||
* Compatibility: add a new conditional, `\Activitypub\is_activitypub_request()`, to allow third-party plugins to detect ActivityPub requests.
|
||||
* Compatibility: add hooks to allow modifying images returned in ActivityPub requests.
|
||||
* Compatibility: indicate that the plugin is compatible and has been tested with the latest version of WordPress, 6.2.
|
||||
|
||||
### 0.17.0 ###
|
||||
|
|
169
activitypub.php
169
activitypub.php
|
@ -15,6 +15,8 @@
|
|||
|
||||
namespace Activitypub;
|
||||
|
||||
\defined( 'ACTIVITYPUB_REST_NAMESPACE' ) || \define( 'ACTIVITYPUB_REST_NAMESPACE', 'activitypub/1.0' );
|
||||
|
||||
/**
|
||||
* Initialize plugin
|
||||
*/
|
||||
|
@ -30,76 +32,72 @@ function init() {
|
|||
\define( 'ACTIVITYPUB_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
|
||||
\define( 'ACTIVITYPUB_PLUGIN_FILE', plugin_dir_path( __FILE__ ) . '/' . basename( __FILE__ ) );
|
||||
|
||||
\define( 'ACTIVITYPUB_OBJECT', 'ACTIVITYPUB_OBJECT' );
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/table/class-followers.php';
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-http.php';
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-signature.php';
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-webfinger.php';
|
||||
require_once \dirname( __FILE__ ) . '/includes/peer/class-followers.php';
|
||||
require_once \dirname( __FILE__ ) . '/includes/functions.php';
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/model/class-activity.php';
|
||||
require_once \dirname( __FILE__ ) . '/includes/model/class-post.php';
|
||||
require_once \dirname( __FILE__ ) . '/includes/model/class-follower.php';
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-migration.php';
|
||||
Migration::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-activity-dispatcher.php';
|
||||
Activity_Dispatcher::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-activitypub.php';
|
||||
Activitypub::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/collection/class-followers.php';
|
||||
Activity_Dispatcher::init();
|
||||
Collection\Followers::init();
|
||||
|
||||
// Configure the REST API route
|
||||
require_once \dirname( __FILE__ ) . '/includes/rest/class-outbox.php';
|
||||
Rest\Outbox::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/rest/class-inbox.php';
|
||||
Rest\Inbox::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/rest/class-followers.php';
|
||||
Rest\Followers::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/rest/class-following.php';
|
||||
Rest\Following::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/rest/class-webfinger.php';
|
||||
Rest\Webfinger::init();
|
||||
|
||||
Admin::init();
|
||||
Hashtag::init();
|
||||
Shortcodes::init();
|
||||
Mention::init();
|
||||
Health_Check::init();
|
||||
Scheduler::init();
|
||||
}
|
||||
\add_action( 'plugins_loaded', __NAMESPACE__ . '\init' );
|
||||
|
||||
/**
|
||||
* Class Autoloader
|
||||
*/
|
||||
spl_autoload_register(
|
||||
function ( $full_class ) {
|
||||
$base_dir = \dirname( __FILE__ ) . '/includes/';
|
||||
$base = 'activitypub';
|
||||
|
||||
$class = strtolower( $full_class );
|
||||
|
||||
if ( strncmp( $class, $base, strlen( $base ) ) === 0 ) {
|
||||
$class = str_replace( 'activitypub\\', '', $class );
|
||||
|
||||
if ( false !== strpos( $class, '\\' ) ) {
|
||||
$parts = explode( '\\', $class );
|
||||
$class = array_pop( $parts );
|
||||
$sub_dir = implode( '/', $parts );
|
||||
$base_dir = $base_dir . $sub_dir . '/';
|
||||
}
|
||||
|
||||
$filename = 'class-' . strtr( $class, '_', '-' );
|
||||
$file = $base_dir . $filename . '.php';
|
||||
|
||||
if ( file_exists( $file ) && is_readable( $file ) ) {
|
||||
require_once $file;
|
||||
} else {
|
||||
// translators: %s is the class name
|
||||
\wp_die( sprintf( esc_html__( 'Required class not found or not readable: %s', 'activitypub' ), esc_html( $full_class ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/functions.php';
|
||||
|
||||
// load NodeInfo endpoints only if blog is public
|
||||
if ( true === (bool) \get_option( 'blog_public', 1 ) ) {
|
||||
require_once \dirname( __FILE__ ) . '/includes/rest/class-nodeinfo.php';
|
||||
if ( \get_option( 'blog_public', 1 ) ) {
|
||||
Rest\NodeInfo::init();
|
||||
}
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-admin.php';
|
||||
Admin::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-hashtag.php';
|
||||
Hashtag::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-shortcodes.php';
|
||||
Shortcodes::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-mention.php';
|
||||
Mention::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-debug.php';
|
||||
$debug_file = \dirname( __FILE__ ) . '/includes/debug.php';
|
||||
if ( \WP_DEBUG && file_exists( $debug_file ) && is_readable( $debug_file ) ) {
|
||||
require_once $debug_file;
|
||||
Debug::init();
|
||||
|
||||
require_once \dirname( __FILE__ ) . '/includes/class-health-check.php';
|
||||
Health_Check::init();
|
||||
|
||||
if ( \WP_DEBUG ) {
|
||||
require_once \dirname( __FILE__ ) . '/includes/debug.php';
|
||||
}
|
||||
}
|
||||
\add_action( 'plugins_loaded', '\Activitypub\init' );
|
||||
|
||||
/**
|
||||
* Add plugin settings link
|
||||
|
@ -113,43 +111,54 @@ function plugin_settings_link( $actions ) {
|
|||
|
||||
return \array_merge( $settings_link, $actions );
|
||||
}
|
||||
\add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), '\Activitypub\plugin_settings_link' );
|
||||
\add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), __NAMESPACE__ . '\plugin_settings_link' );
|
||||
|
||||
/**
|
||||
* Add rewrite rules
|
||||
*/
|
||||
function add_rewrite_rules() {
|
||||
if ( ! \class_exists( 'Webfinger' ) ) {
|
||||
\add_rewrite_rule( '^.well-known/webfinger', 'index.php?rest_route=/activitypub/1.0/webfinger', 'top' );
|
||||
}
|
||||
\register_activation_hook(
|
||||
__FILE__,
|
||||
array(
|
||||
__NAMESPACE__ . '\Activitypub',
|
||||
'activate',
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! \class_exists( 'Nodeinfo' ) || ! (bool) \get_option( 'blog_public', 1 ) ) {
|
||||
\add_rewrite_rule( '^.well-known/nodeinfo', 'index.php?rest_route=/activitypub/1.0/nodeinfo/discovery', 'top' );
|
||||
\add_rewrite_rule( '^.well-known/x-nodeinfo2', 'index.php?rest_route=/activitypub/1.0/nodeinfo2', 'top' );
|
||||
}
|
||||
\register_deactivation_hook(
|
||||
__FILE__,
|
||||
array(
|
||||
__NAMESPACE__ . '\Activitypub',
|
||||
'deactivate',
|
||||
)
|
||||
);
|
||||
|
||||
\add_rewrite_endpoint( 'activitypub', EP_AUTHORS | EP_PERMALINK | EP_PAGES );
|
||||
}
|
||||
\add_action( 'init', '\Activitypub\add_rewrite_rules', 1 );
|
||||
|
||||
/**
|
||||
* Flush rewrite rules;
|
||||
*/
|
||||
function flush_rewrite_rules() {
|
||||
\Activitypub\add_rewrite_rules();
|
||||
\flush_rewrite_rules();
|
||||
}
|
||||
\register_activation_hook( __FILE__, '\Activitypub\flush_rewrite_rules' );
|
||||
\register_deactivation_hook( __FILE__, '\flush_rewrite_rules' );
|
||||
\register_uninstall_hook(
|
||||
__FILE__,
|
||||
array(
|
||||
__NAMESPACE__ . '\Activitypub',
|
||||
'uninstall',
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Only load code that needs BuddyPress to run once BP is loaded and initialized.
|
||||
*/
|
||||
function enable_buddypress_features() {
|
||||
add_action(
|
||||
'bp_include',
|
||||
function() {
|
||||
require_once \dirname( __FILE__ ) . '/integration/class-buddypress.php';
|
||||
Integration\Buddypress::init();
|
||||
},
|
||||
0
|
||||
);
|
||||
|
||||
add_action(
|
||||
'plugins_loaded',
|
||||
function() {
|
||||
if ( defined( 'WP_SWEEP_VERSION' ) ) {
|
||||
require_once \dirname( __FILE__ ) . '/integration/class-wp-sweep.php';
|
||||
Integration\Wp_Sweep::init();
|
||||
}
|
||||
add_action( 'bp_include', '\Activitypub\enable_buddypress_features' );
|
||||
},
|
||||
0
|
||||
);
|
||||
|
||||
/**
|
||||
* `get_plugin_data` wrapper
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"squizlabs/php_codesniffer": "3.*",
|
||||
"wp-coding-standards/wpcs": "*",
|
||||
"yoast/phpunit-polyfills": "^1.0",
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.1"
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "^1.0.0"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": true
|
||||
|
|
|
@ -22,9 +22,40 @@ class Activitypub {
|
|||
\add_post_type_support( $post_type, 'activitypub' );
|
||||
}
|
||||
|
||||
\add_action( 'transition_post_status', array( self::class, 'schedule_post_activity' ), 33, 3 );
|
||||
\add_action( 'wp_trash_post', array( self::class, 'trash_post' ), 1 );
|
||||
\add_action( 'untrash_post', array( self::class, 'untrash_post' ), 1 );
|
||||
|
||||
\add_action( 'init', array( self::class, 'add_rewrite_rules' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Activation Hook
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function activate() {
|
||||
self::flush_rewrite_rules();
|
||||
|
||||
Scheduler::register_schedules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivation Hook
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function deactivate() {
|
||||
self::flush_rewrite_rules();
|
||||
|
||||
Scheduler::deregister_schedules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall Hook
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall() {
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -98,36 +129,6 @@ class Activitypub {
|
|||
return $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule Activities.
|
||||
*
|
||||
* @param string $new_status New post status.
|
||||
* @param string $old_status Old post status.
|
||||
* @param WP_Post $post Post object.
|
||||
*/
|
||||
public static function schedule_post_activity( $new_status, $old_status, $post ) {
|
||||
// Do not send activities if post is password protected.
|
||||
if ( \post_password_required( $post ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if post-type supports ActivityPub.
|
||||
$post_types = \get_post_types_by_support( 'activitypub' );
|
||||
if ( ! \in_array( $post->post_type, $post_types, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$activitypub_post = new \Activitypub\Model\Post( $post );
|
||||
|
||||
if ( 'publish' === $new_status && 'publish' !== $old_status ) {
|
||||
\wp_schedule_single_event( \time(), 'activitypub_send_create_activity', array( $activitypub_post ) );
|
||||
} elseif ( 'publish' === $new_status ) {
|
||||
\wp_schedule_single_event( \time(), 'activitypub_send_update_activity', array( $activitypub_post ) );
|
||||
} elseif ( 'trash' === $new_status ) {
|
||||
\wp_schedule_single_event( \time(), 'activitypub_send_delete_activity', array( $activitypub_post ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the default avatar.
|
||||
*
|
||||
|
@ -146,7 +147,14 @@ class Activitypub {
|
|||
}
|
||||
|
||||
$allowed_comment_types = \apply_filters( 'get_avatar_comment_types', array( 'comment' ) );
|
||||
if ( ! empty( $id_or_email->comment_type ) && ! \in_array( $id_or_email->comment_type, (array) $allowed_comment_types, true ) ) {
|
||||
if (
|
||||
! empty( $id_or_email->comment_type ) &&
|
||||
! \in_array(
|
||||
$id_or_email->comment_type,
|
||||
(array) $allowed_comment_types,
|
||||
true
|
||||
)
|
||||
) {
|
||||
$args['url'] = false;
|
||||
/** This filter is documented in wp-includes/link-template.php */
|
||||
return \apply_filters( 'get_avatar_data', $args, $id_or_email );
|
||||
|
@ -191,7 +199,12 @@ class Activitypub {
|
|||
* @return void
|
||||
*/
|
||||
public static function trash_post( $post_id ) {
|
||||
\add_post_meta( $post_id, 'activitypub_canonical_url', \get_permalink( $post_id ), true );
|
||||
\add_post_meta(
|
||||
$post_id,
|
||||
'activitypub_canonical_url',
|
||||
\get_permalink( $post_id ),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -204,4 +217,40 @@ class Activitypub {
|
|||
public static function untrash_post( $post_id ) {
|
||||
\delete_post_meta( $post_id, 'activitypub_canonical_url' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add rewrite rules
|
||||
*/
|
||||
public static function add_rewrite_rules() {
|
||||
if ( ! \class_exists( 'Webfinger' ) ) {
|
||||
\add_rewrite_rule(
|
||||
'^.well-known/webfinger',
|
||||
'index.php?rest_route=/' . ACTIVITYPUB_REST_NAMESPACE . '/webfinger',
|
||||
'top'
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! \class_exists( 'Nodeinfo' ) && true === (bool) \get_option( 'blog_public', 1 ) ) {
|
||||
\add_rewrite_rule(
|
||||
'^.well-known/nodeinfo',
|
||||
'index.php?rest_route=/' . ACTIVITYPUB_REST_NAMESPACE . '/nodeinfo/discovery',
|
||||
'top'
|
||||
);
|
||||
\add_rewrite_rule(
|
||||
'^.well-known/x-nodeinfo2',
|
||||
'index.php?rest_route=/' . ACTIVITYPUB_REST_NAMESPACE . '/nodeinfo2',
|
||||
'top'
|
||||
);
|
||||
}
|
||||
|
||||
\add_rewrite_endpoint( 'activitypub', EP_AUTHORS | EP_PERMALINK | EP_PAGES );
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush rewrite rules;
|
||||
*/
|
||||
public static function flush_rewrite_rules() {
|
||||
self::add_rewrite_rules();
|
||||
\flush_rewrite_rules();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
<?php
|
||||
namespace Activitypub;
|
||||
|
||||
use Acctivitypub\Model\Follower;
|
||||
use Activitypub\Model\Follower;
|
||||
use Activitypub\Collection\Followers;
|
||||
|
||||
/**
|
||||
* ActivityPub Migration Class
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*/
|
||||
class Migration {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
*/
|
||||
public static function init() {
|
||||
\add_action( 'activitypub_schedule_migration', array( self::class, 'maybe_migrate' ) );
|
||||
}
|
||||
|
@ -74,7 +83,7 @@ class Migration {
|
|||
|
||||
$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(), Followers::TAXONOMY, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
138
includes/class-scheduler.php
Normal file
138
includes/class-scheduler.php
Normal file
|
@ -0,0 +1,138 @@
|
|||
<?php
|
||||
|
||||
namespace Activitypub;
|
||||
|
||||
use Activitypub\Model\Post;
|
||||
use Activitypub\Collection\Followers;
|
||||
|
||||
/**
|
||||
* ActivityPub Scheduler Class
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*/
|
||||
class Scheduler {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
*/
|
||||
public static function init() {
|
||||
\add_action( 'transition_post_status', array( self::class, 'schedule_post_activity' ), 33, 3 );
|
||||
|
||||
\add_action( 'activitypub_update_followers', array( self::class, 'update_followers' ) );
|
||||
\add_action( 'activitypub_cleanup_followers', array( self::class, 'cleanup_followers' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule all ActivityPub schedules.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function register_schedules() {
|
||||
if ( ! \wp_next_scheduled( 'activitypub_update_followers' ) ) {
|
||||
\wp_schedule_event( time(), 'hourly', 'activitypub_update_followers' );
|
||||
}
|
||||
|
||||
if ( ! \wp_next_scheduled( 'activitypub_cleanup_followers' ) ) {
|
||||
\wp_schedule_event( time(), 'daily', 'activitypub_cleanup_followers' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unscedule all ActivityPub schedules.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function deregister_schedules() {
|
||||
wp_unschedule_hook( 'activitypub_update_followers' );
|
||||
wp_unschedule_hook( 'activitypub_cleanup_followers' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Schedule Activities.
|
||||
*
|
||||
* @param string $new_status New post status.
|
||||
* @param string $old_status Old post status.
|
||||
* @param WP_Post $post Post object.
|
||||
*/
|
||||
public static function schedule_post_activity( $new_status, $old_status, $post ) {
|
||||
// Do not send activities if post is password protected.
|
||||
if ( \post_password_required( $post ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if post-type supports ActivityPub.
|
||||
$post_types = \get_post_types_by_support( 'activitypub' );
|
||||
if ( ! \in_array( $post->post_type, $post_types, true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$activitypub_post = new Post( $post );
|
||||
|
||||
if ( 'publish' === $new_status && 'publish' !== $old_status ) {
|
||||
\wp_schedule_single_event(
|
||||
\time(),
|
||||
'activitypub_send_create_activity',
|
||||
array( $activitypub_post )
|
||||
);
|
||||
} elseif ( 'publish' === $new_status ) {
|
||||
\wp_schedule_single_event(
|
||||
\time(),
|
||||
'activitypub_send_update_activity',
|
||||
array( $activitypub_post )
|
||||
);
|
||||
} elseif ( 'trash' === $new_status ) {
|
||||
\wp_schedule_single_event(
|
||||
\time(),
|
||||
'activitypub_send_delete_activity',
|
||||
array( $activitypub_post )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update followers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function update_followers() {
|
||||
$followers = Followers::get_outdated_followers();
|
||||
|
||||
foreach ( $followers as $follower ) {
|
||||
$meta = get_remote_metadata_by_actor( $follower->get_actor() );
|
||||
|
||||
if ( empty( $meta ) || ! is_array( $meta ) || is_wp_error( $meta ) ) {
|
||||
$follower->set_error( $meta );
|
||||
} else {
|
||||
$follower->from_meta( $meta );
|
||||
}
|
||||
|
||||
$follower->update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup followers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function cleanup_followers() {
|
||||
$followers = Followers::get_faulty_followers();
|
||||
|
||||
foreach ( $followers as $follower ) {
|
||||
$meta = get_remote_metadata_by_actor( $follower->get_actor() );
|
||||
|
||||
if ( is_tombstone( $meta ) ) {
|
||||
$follower->delete();
|
||||
} elseif ( empty( $meta ) || ! is_array( $meta ) || is_wp_error( $meta ) ) {
|
||||
if ( 5 <= $follower->count_errors() ) {
|
||||
$follower->delete();
|
||||
} else {
|
||||
$follower->set_error( $meta );
|
||||
$follower->update();
|
||||
}
|
||||
} else {
|
||||
$follower->reset_errors();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,9 +6,9 @@ class Shortcodes {
|
|||
* Class constructor, registering WordPress then Shortcodes
|
||||
*/
|
||||
public static function init() {
|
||||
foreach ( get_class_methods( 'Activitypub\Shortcodes' ) as $shortcode ) {
|
||||
foreach ( get_class_methods( self::class ) as $shortcode ) {
|
||||
if ( 'init' !== $shortcode ) {
|
||||
add_shortcode( 'ap_' . $shortcode, array( 'Activitypub\Shortcodes', $shortcode ) );
|
||||
add_shortcode( 'ap_' . $shortcode, array( self::class, $shortcode ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ use function Activitypub\get_remote_metadata_by_actor;
|
|||
*/
|
||||
class Followers {
|
||||
const TAXONOMY = 'activitypub-followers';
|
||||
const CACHE_KEY_INBOXES = 'follower_inboxes_%s';
|
||||
|
||||
/**
|
||||
* Register WordPress hooks/actions and register Taxonomy
|
||||
|
@ -143,7 +144,7 @@ class Followers {
|
|||
'single' => true,
|
||||
'sanitize_callback' => function( $value ) {
|
||||
if ( ! is_numeric( $value ) && (int) $value !== $value ) {
|
||||
$value = strtotime( 'now' );
|
||||
$value = \time();
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
@ -186,7 +187,7 @@ class Followers {
|
|||
}
|
||||
|
||||
/**
|
||||
* Handles "Unfollow" requests
|
||||
* Handle "Unfollow" requests
|
||||
*
|
||||
* @param array $object The JSON "Undo" Activity
|
||||
* @param int $user_id The ID of the ID of the WordPress User
|
||||
|
@ -202,7 +203,7 @@ class Followers {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a new Follower
|
||||
* Add new Follower
|
||||
*
|
||||
* @param int $user_id The ID of the WordPress User
|
||||
* @param string $actor The Actor URL
|
||||
|
@ -225,6 +226,7 @@ class Followers {
|
|||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
} else {
|
||||
wp_cache_delete( sprintf( self::CACHE_KEY_INBOXES, $user_id ), 'activitypub' );
|
||||
return $follower;
|
||||
}
|
||||
}
|
||||
|
@ -238,6 +240,7 @@ class Followers {
|
|||
* @return bool|WP_Error True on success, false or WP_Error on failure.
|
||||
*/
|
||||
public static function remove_follower( $user_id, $actor ) {
|
||||
wp_cache_delete( sprintf( self::CACHE_KEY_INBOXES, $user_id ), 'activitypub' );
|
||||
return wp_remove_object_terms( $user_id, $actor, self::TAXONOMY );
|
||||
}
|
||||
|
||||
|
@ -316,7 +319,7 @@ 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, $args = array() ) {
|
||||
public static function get_followers( $user_id, $number = null, $offset = null, $args = array() ) {
|
||||
$defaults = array(
|
||||
'taxonomy' => self::TAXONOMY,
|
||||
'hide_empty' => false,
|
||||
|
@ -329,25 +332,32 @@ class Followers {
|
|||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
$terms = new WP_Term_Query( $args );
|
||||
|
||||
$items = array();
|
||||
|
||||
// change output format
|
||||
switch ( $output ) {
|
||||
case ACTIVITYPUB_OBJECT:
|
||||
foreach ( $terms->get_terms() as $follower ) {
|
||||
$items[] = new Follower( $follower->name ); // phpcs:ignore
|
||||
}
|
||||
|
||||
return $items;
|
||||
case OBJECT:
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all Followers
|
||||
*
|
||||
* @param array $args The WP_Term_Query arguments.
|
||||
*
|
||||
* @return array The Term list of Followers.
|
||||
*/
|
||||
public static function get_all_followers( $args = array() ) {
|
||||
$defaults = array(
|
||||
'taxonomy' => self::TAXONOMY,
|
||||
'hide_empty' => false,
|
||||
);
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
$terms = new WP_Term_Query( $args );
|
||||
|
||||
return $terms->get_terms();
|
||||
case ARRAY_N:
|
||||
default:
|
||||
foreach ( $terms->get_terms() as $follower ) {
|
||||
$items[] = $follower->name; // phpcs:ignore
|
||||
}
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -369,6 +379,13 @@ class Followers {
|
|||
* @return array The list of Inboxes
|
||||
*/
|
||||
public static function get_inboxes( $user_id ) {
|
||||
$cache_key = sprintf( self::CACHE_KEY_INBOXES, $user_id );
|
||||
$inboxes = wp_cache_get( $cache_key, 'activitypub' );
|
||||
|
||||
if ( $inboxes ) {
|
||||
return $inboxes;
|
||||
}
|
||||
|
||||
// get all Followers of a ID of the WordPress User
|
||||
$terms = new WP_Term_Query(
|
||||
array(
|
||||
|
@ -402,6 +419,75 @@ class Followers {
|
|||
)
|
||||
);
|
||||
|
||||
return array_filter( $results );
|
||||
$inboxes = array_filter( $results );
|
||||
wp_cache_set( $cache_key, $inboxes, 'activitypub' );
|
||||
|
||||
return $inboxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all Followers that have not been updated for a given time
|
||||
*
|
||||
* @param enum $output The output format, supported ARRAY_N, OBJECT and ACTIVITYPUB_OBJECT.
|
||||
* @param int $number Limits the result.
|
||||
* @param int $older_than The time in seconds.
|
||||
*
|
||||
* @return mixed The Term list of Followers, the format depends on $output.
|
||||
*/
|
||||
public static function get_outdated_followers( $number = 50, $older_than = 604800 ) {
|
||||
$args = array(
|
||||
'taxonomy' => self::TAXONOMY,
|
||||
'number' => $number,
|
||||
'meta_key' => 'updated_at',
|
||||
'orderby' => 'meta_value_num',
|
||||
'order' => 'DESC',
|
||||
'meta_query' => array(
|
||||
array(
|
||||
'key' => 'updated_at',
|
||||
'value' => time() - $older_than,
|
||||
'type' => 'numeric',
|
||||
'compare' => '<=',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$terms = new WP_Term_Query( $args );
|
||||
$items = array();
|
||||
|
||||
foreach ( $terms->get_terms() as $follower ) {
|
||||
$items[] = new Follower( $follower->name ); // phpcs:ignore
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all Followers that had errors
|
||||
*
|
||||
* @param enum $output The output format, supported ARRAY_N, OBJECT and ACTIVITYPUB_OBJECT
|
||||
* @param integer $number The number of Followers to return.
|
||||
*
|
||||
* @return mixed The Term list of Followers, the format depends on $output.
|
||||
*/
|
||||
public static function get_faulty_followers( $number = 10 ) {
|
||||
$args = array(
|
||||
'taxonomy' => self::TAXONOMY,
|
||||
'number' => $number,
|
||||
'meta_query' => array(
|
||||
array(
|
||||
'key' => 'errors',
|
||||
'compare' => 'EXISTS',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$terms = new WP_Term_Query( $args );
|
||||
$items = array();
|
||||
|
||||
foreach ( $terms->get_terms() as $follower ) {
|
||||
$items[] = new Follower( $follower->name ); // phpcs:ignore
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,7 +205,7 @@ function get_author_description( $user_id ) {
|
|||
if ( empty( $description ) ) {
|
||||
$description = get_user_meta( $user_id, 'description', true );
|
||||
}
|
||||
return $description;
|
||||
return \wpautop( \wp_kses( $description, 'default' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,3 +228,61 @@ function is_tombstone( $wp_error ) {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the REST URL relative to this plugin's namespace.
|
||||
*
|
||||
* @param string $path Optional. REST route path. Otherwise this plugin's namespaced root.
|
||||
*
|
||||
* @return string REST URL relative to this plugin's namespace.
|
||||
*/
|
||||
function get_rest_url_by_path( $path = '' ) {
|
||||
// we'll handle the leading slash.
|
||||
$path = ltrim( $path, '/' );
|
||||
$namespaced_path = sprintf( '/%s/%s', ACTIVITYPUB_REST_NAMESPACE, $path );
|
||||
return \get_rest_url( null, $namespaced_path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a request is for an ActivityPub request.
|
||||
*
|
||||
* @return bool False by default.
|
||||
*/
|
||||
function is_activitypub_request() {
|
||||
global $wp_query;
|
||||
|
||||
/*
|
||||
* ActivityPub requests are currently only made for
|
||||
* author archives, singular posts, and the homepage.
|
||||
*/
|
||||
if ( ! \is_author() && ! \is_singular() && ! \is_home() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// One can trigger an ActivityPub request by adding ?activitypub to the URL.
|
||||
global $wp_query;
|
||||
if ( isset( $wp_query->query_vars['activitypub'] ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The other (more common) option to make an ActivityPub request
|
||||
* is to send an Accept header.
|
||||
*/
|
||||
if ( isset( $_SERVER['HTTP_ACCEPT'] ) ) {
|
||||
$accept = $_SERVER['HTTP_ACCEPT'];
|
||||
|
||||
/*
|
||||
* $accept can be a single value, or a comma separated list of values.
|
||||
* We want to support both scenarios,
|
||||
* and return true when the header includes at least one of the following:
|
||||
* - application/activity+json
|
||||
* - application/ld+json
|
||||
*/
|
||||
if ( preg_match( '/(application\/(ld\+json|activity\+json))/', $accept ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
namespace Activitypub\Model;
|
||||
|
||||
use function Activitypub\get_rest_url_by_path;
|
||||
|
||||
/**
|
||||
* ActivityPub Post Class
|
||||
*
|
||||
|
@ -97,7 +99,7 @@ class Activity {
|
|||
}
|
||||
|
||||
$this->type = \ucfirst( $type );
|
||||
$this->published = \gmdate( 'Y-m-d\TH:i:s\Z', \strtotime( 'now' ) );
|
||||
$this->published = \gmdate( 'Y-m-d\TH:i:s\Z', \time() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -148,7 +150,8 @@ class Activity {
|
|||
$this->published = $object['published'];
|
||||
}
|
||||
|
||||
$this->add_to( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $post->get_post_author() ) . '/followers' ) );
|
||||
$path = sprintf( 'users/%d/followers', intval( $post->get_post_author() ) );
|
||||
$this->add_to( get_rest_url_by_path( $path ) );
|
||||
|
||||
if ( isset( $this->object['attributedTo'] ) ) {
|
||||
$this->actor = $this->object['attributedTo'];
|
||||
|
|
|
@ -139,8 +139,8 @@ class Follower {
|
|||
/**
|
||||
* Magic function to implement getter and setter
|
||||
*
|
||||
* @param string $method
|
||||
* @param string $params
|
||||
* @param string $method The method name.
|
||||
* @param string $params The method params.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
@ -159,6 +159,22 @@ class Follower {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic function to return the Actor-URL when the Object is used as a string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString() {
|
||||
return $this->get_actor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefill the Object with the meta data.
|
||||
*
|
||||
* @param array $meta The meta data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function from_meta( $meta ) {
|
||||
$this->meta = $meta;
|
||||
|
||||
|
@ -178,9 +194,16 @@ class Follower {
|
|||
$this->shared_inbox = $meta['inbox'];
|
||||
}
|
||||
|
||||
$this->updated_at = \strtotime( 'now' );
|
||||
$this->updated_at = \time();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data by the given attribute
|
||||
*
|
||||
* @param string $attribute The attribute name.
|
||||
*
|
||||
* @return mixed The attribute value.
|
||||
*/
|
||||
public function get( $attribute ) {
|
||||
if ( $this->$attribute ) {
|
||||
return $this->$attribute;
|
||||
|
@ -201,6 +224,23 @@ class Follower {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new Error
|
||||
*
|
||||
* @param mixed $error The latest HTTP-Error.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_error( $error ) {
|
||||
$this->errors = array();
|
||||
$this->error = $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the errors.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_errors() {
|
||||
if ( $this->errors ) {
|
||||
return $this->errors;
|
||||
|
@ -210,6 +250,20 @@ class Follower {
|
|||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset (delete) all errors.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reset_errors() {
|
||||
delete_term_meta( $this->id, 'errors' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the errors.
|
||||
*
|
||||
* @return int The number of errors.
|
||||
*/
|
||||
public function count_errors() {
|
||||
$errors = $this->get_errors();
|
||||
|
||||
|
@ -220,6 +274,11 @@ class Follower {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the latest error message.
|
||||
*
|
||||
* @return string The error message.
|
||||
*/
|
||||
public function get_latest_error_message() {
|
||||
$errors = $this->get_errors();
|
||||
|
||||
|
@ -230,6 +289,13 @@ class Follower {
|
|||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the meta data by the given attribute.
|
||||
*
|
||||
* @param string $attribute The attribute name.
|
||||
*
|
||||
* @return mixed $attribute The attribute value.
|
||||
*/
|
||||
public function get_meta_by( $attribute ) {
|
||||
$meta = $this->get_meta();
|
||||
|
||||
|
@ -248,6 +314,11 @@ class Follower {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the meta data.
|
||||
*
|
||||
* @return array $meta The meta data.
|
||||
*/
|
||||
public function get_meta() {
|
||||
if ( $this->meta ) {
|
||||
return $this->meta;
|
||||
|
@ -256,6 +327,11 @@ class Follower {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current Follower-Object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update() {
|
||||
$term = wp_update_term(
|
||||
$this->id,
|
||||
|
@ -265,10 +341,15 @@ class Follower {
|
|||
)
|
||||
);
|
||||
|
||||
$this->updated_at = \strtotime( 'now' );
|
||||
$this->updated_at = \time();
|
||||
$this->update_term_meta();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current Follower-Object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save() {
|
||||
$term = wp_insert_term(
|
||||
$this->actor,
|
||||
|
@ -284,6 +365,11 @@ class Follower {
|
|||
$this->update_term_meta();
|
||||
}
|
||||
|
||||
/**
|
||||
* Upsert the current Follower-Object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function upsert() {
|
||||
if ( $this->id ) {
|
||||
$this->update();
|
||||
|
@ -292,6 +378,20 @@ class Follower {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the current Follower-Object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function delete() {
|
||||
wp_delete_term( $this->id, Followers::TAXONOMY );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the term meta.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function update_term_meta() {
|
||||
$attributes = array( 'inbox', 'shared_inbox', 'avatar', 'updated_at', 'name', 'username' );
|
||||
|
||||
|
@ -312,6 +412,5 @@ class Follower {
|
|||
|
||||
add_term_meta( $this->id, 'errors', $error );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
namespace Activitypub\Model;
|
||||
|
||||
use function Activitypub\get_rest_url_by_path;
|
||||
|
||||
/**
|
||||
* ActivityPub Post Class
|
||||
*
|
||||
|
@ -93,8 +95,13 @@ class Post {
|
|||
'class' => array(),
|
||||
),
|
||||
'ul' => array(),
|
||||
'ol' => array(),
|
||||
'li' => array(),
|
||||
'ol' => array(
|
||||
'reversed' => array(),
|
||||
'start' => array(),
|
||||
),
|
||||
'li' => array(
|
||||
'value' => array(),
|
||||
),
|
||||
'strong' => array(
|
||||
'class' => array(),
|
||||
),
|
||||
|
@ -142,7 +149,8 @@ class Post {
|
|||
*/
|
||||
public function __construct( $post ) {
|
||||
$this->post = \get_post( $post );
|
||||
$this->add_to( \get_rest_url( null, '/activitypub/1.0/users/' . intval( $this->get_post_author() ) . '/followers' ) );
|
||||
$path = sprintf( 'users/%d/followers', intval( $this->get_post_author() ) );
|
||||
$this->add_to( get_rest_url_by_path( $path ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -539,6 +547,6 @@ class Post {
|
|||
return "[ap_content]\n\n[ap_hashtags]\n\n[ap_permalink type=\"html\"]";
|
||||
}
|
||||
|
||||
return \get_option( 'activitypub_custom_post_content' );
|
||||
return \get_option( 'activitypub_custom_post_content', ACTIVITYPUB_CUSTOM_POST_CONTENT );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ use WP_REST_Server;
|
|||
use WP_REST_Response;
|
||||
use Activitypub\Collection\Followers as FollowerCollection;
|
||||
|
||||
use function Activitypub\get_rest_url_by_path;
|
||||
|
||||
/**
|
||||
* ActivityPub Followers REST-Class
|
||||
*
|
||||
|
@ -27,7 +29,7 @@ class Followers {
|
|||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/users/(?P<user_id>\d+)/followers',
|
||||
array(
|
||||
array(
|
||||
|
@ -78,10 +80,16 @@ class Followers {
|
|||
$json->actor = \get_author_posts_url( $user_id );
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
|
||||
$json->partOf = \get_rest_url( null, "/activitypub/1.0/users/$user_id/followers" ); // phpcs:ignore
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'users/%d/followers', $user_id ) ); // phpcs:ignore
|
||||
$json->first = $json->partOf; // phpcs:ignore
|
||||
$json->totalItems = FollowerCollection::count_followers( $user_id ); // phpcs:ignore
|
||||
$json->orderedItems = FollowerCollection::get_followers( $user_id, ARRAY_N ); // phpcs:ignore
|
||||
// phpcs:ignore
|
||||
$json->orderedItems = array_map(
|
||||
function( $item ) {
|
||||
return $item->get_actor();
|
||||
},
|
||||
FollowerCollection::get_followers( $user_id )
|
||||
);
|
||||
|
||||
$response = new WP_REST_Response( $json, 200 );
|
||||
$response->header( 'Content-Type', 'application/activity+json' );
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use function Activitypub\get_rest_url_by_path;
|
||||
|
||||
/**
|
||||
* ActivityPub Following REST-Class
|
||||
*
|
||||
|
@ -21,7 +23,7 @@ class Following {
|
|||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/users/(?P<user_id>\d+)/following',
|
||||
array(
|
||||
array(
|
||||
|
@ -72,7 +74,7 @@ class Following {
|
|||
$json->actor = \get_author_posts_url( $user_id );
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
|
||||
$json->partOf = \get_rest_url( null, "/activitypub/1.0/users/$user_id/following" ); // phpcs:ignore
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'users/%d/following', $user_id ) ); // phpcs:ignore
|
||||
$json->totalItems = 0; // phpcs:ignore
|
||||
$json->orderedItems = apply_filters( 'activitypub_following', array(), $user ); // phpcs:ignore
|
||||
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
<?php
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_Error;
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Response;
|
||||
use Activitypub\Model\Activity;
|
||||
|
||||
use function Activitypub\get_context;
|
||||
use function Activitypub\url_to_authorid;
|
||||
use function Activitypub\get_rest_url_by_path;
|
||||
use function Activitypub\get_remote_metadata_by_actor;
|
||||
|
||||
/**
|
||||
* ActivityPub Inbox REST-Class
|
||||
*
|
||||
|
@ -26,11 +34,11 @@ class Inbox {
|
|||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/inbox',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::EDITABLE,
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( self::class, 'shared_inbox_post' ),
|
||||
'args' => self::shared_inbox_post_parameters(),
|
||||
'permission_callback' => '__return_true',
|
||||
|
@ -39,17 +47,17 @@ class Inbox {
|
|||
);
|
||||
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/users/(?P<user_id>\d+)/inbox',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::EDITABLE,
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( self::class, 'user_inbox_post' ),
|
||||
'args' => self::user_inbox_post_parameters(),
|
||||
'permission_callback' => '__return_true',
|
||||
),
|
||||
array(
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( self::class, 'user_inbox_get' ),
|
||||
'args' => self::user_inbox_get_parameters(),
|
||||
'permission_callback' => '__return_true',
|
||||
|
@ -104,11 +112,11 @@ class Inbox {
|
|||
|
||||
$json = new \stdClass();
|
||||
|
||||
$json->{'@context'} = \Activitypub\get_context();
|
||||
$json->{'@context'} = get_context();
|
||||
$json->id = \home_url( \add_query_arg( null, null ) );
|
||||
$json->generator = 'http://wordpress.org/?v=' . \get_bloginfo_rss( 'version' );
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
$json->partOf = \get_rest_url( null, "/activitypub/1.0/users/$user_id/inbox" ); // phpcs:ignore
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'users/%d/inbox', $user_id ) ); // phpcs:ignore
|
||||
|
||||
$json->totalItems = 0; // phpcs:ignore
|
||||
|
||||
|
@ -124,7 +132,7 @@ class Inbox {
|
|||
*/
|
||||
\do_action( 'activitypub_inbox_post' );
|
||||
|
||||
$response = new \WP_REST_Response( $json, 200 );
|
||||
$response = new WP_REST_Response( $json, 200 );
|
||||
|
||||
$response->header( 'Content-Type', 'application/activity+json' );
|
||||
|
||||
|
@ -148,7 +156,7 @@ class Inbox {
|
|||
\do_action( 'activitypub_inbox', $data, $user_id, $type );
|
||||
\do_action( "activitypub_inbox_{$type}", $data, $user_id );
|
||||
|
||||
return new \WP_REST_Response( array(), 202 );
|
||||
return new WP_REST_Response( array(), 202 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,7 +172,7 @@ class Inbox {
|
|||
$users = self::extract_recipients( $data );
|
||||
|
||||
if ( ! $users ) {
|
||||
return new \WP_Error(
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
\__( 'No recipients found', 'activitypub' ),
|
||||
array(
|
||||
|
@ -187,7 +195,7 @@ class Inbox {
|
|||
\do_action( "activitypub_inbox_{$type}", $data, $user->ID );
|
||||
}
|
||||
|
||||
return new \WP_REST_Response( array(), 202 );
|
||||
return new WP_REST_Response( array(), 202 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -348,7 +356,7 @@ class Inbox {
|
|||
* @param int $user_id The id of the local blog-user
|
||||
*/
|
||||
public static function handle_reaction( $object, $user_id ) {
|
||||
$meta = \Activitypub\get_remote_metadata_by_actor( $object['actor'] );
|
||||
$meta = get_remote_metadata_by_actor( $object['actor'] );
|
||||
|
||||
$comment_post_id = \url_to_postid( $object['object'] );
|
||||
|
||||
|
@ -393,7 +401,7 @@ class Inbox {
|
|||
* @param int $user_id The id of the local blog-user
|
||||
*/
|
||||
public static function handle_create( $object, $user_id ) {
|
||||
$meta = \Activitypub\get_remote_metadata_by_actor( $object['actor'] );
|
||||
$meta = get_remote_metadata_by_actor( $object['actor'] );
|
||||
|
||||
if ( ! isset( $object['object']['inReplyTo'] ) ) {
|
||||
return;
|
||||
|
@ -500,7 +508,7 @@ class Inbox {
|
|||
$users = array();
|
||||
|
||||
foreach ( $recipients as $recipient ) {
|
||||
$user_id = \Activitypub\url_to_authorid( $recipient );
|
||||
$user_id = url_to_authorid( $recipient );
|
||||
|
||||
$user = get_user_by( 'id', $user_id );
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use function Activitypub\get_rest_url_by_path;
|
||||
|
||||
/**
|
||||
* ActivityPub NodeInfo REST-Class
|
||||
*
|
||||
|
@ -23,7 +25,7 @@ class Nodeinfo {
|
|||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/nodeinfo/discovery',
|
||||
array(
|
||||
array(
|
||||
|
@ -35,7 +37,7 @@ class Nodeinfo {
|
|||
);
|
||||
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/nodeinfo',
|
||||
array(
|
||||
array(
|
||||
|
@ -47,7 +49,7 @@ class Nodeinfo {
|
|||
);
|
||||
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/nodeinfo2',
|
||||
array(
|
||||
array(
|
||||
|
@ -173,7 +175,7 @@ class Nodeinfo {
|
|||
$discovery['links'] = array(
|
||||
array(
|
||||
'rel' => 'http://nodeinfo.diaspora.software/ns/schema/2.0',
|
||||
'href' => \get_rest_url( null, 'activitypub/1.0/nodeinfo' ),
|
||||
'href' => get_rest_url_by_path( 'nodeinfo' ),
|
||||
),
|
||||
);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class Ostatus {
|
|||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/ostatus/remote-follow',
|
||||
array(
|
||||
array(
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
<?php
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use stdClass;
|
||||
use WP_Error;
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Response;
|
||||
use Activitypub\Model\Post;
|
||||
use Activitypub\Model\Activity;
|
||||
|
||||
use function Activitypub\get_context;
|
||||
use function Activitypub\get_rest_url_by_path;
|
||||
|
||||
/**
|
||||
* ActivityPub Outbox REST-Class
|
||||
*
|
||||
|
@ -21,11 +31,11 @@ class Outbox {
|
|||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/users/(?P<user_id>\d+)/outbox',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( self::class, 'user_outbox_get' ),
|
||||
'args' => self::request_parameters(),
|
||||
'permission_callback' => '__return_true',
|
||||
|
@ -46,7 +56,7 @@ class Outbox {
|
|||
$post_types = \get_option( 'activitypub_support_post_types', array( 'post', 'page' ) );
|
||||
|
||||
if ( ! $author ) {
|
||||
return new \WP_Error(
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
\__( 'User not found', 'activitypub' ),
|
||||
array(
|
||||
|
@ -65,14 +75,14 @@ class Outbox {
|
|||
*/
|
||||
\do_action( 'activitypub_outbox_pre' );
|
||||
|
||||
$json = new \stdClass();
|
||||
$json = new stdClass();
|
||||
|
||||
$json->{'@context'} = \Activitypub\get_context();
|
||||
$json->{'@context'} = get_context();
|
||||
$json->id = \home_url( \add_query_arg( null, null ) );
|
||||
$json->generator = 'http://wordpress.org/?v=' . \get_bloginfo_rss( 'version' );
|
||||
$json->actor = \get_author_posts_url( $user_id );
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
$json->partOf = \get_rest_url( null, "/activitypub/1.0/users/$user_id/outbox" ); // phpcs:ignore
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'users/%d/outbox', $user_id ) ); // phpcs:ignore
|
||||
$json->totalItems = 0; // phpcs:ignore
|
||||
|
||||
// phpcs:ignore
|
||||
|
@ -101,8 +111,8 @@ class Outbox {
|
|||
);
|
||||
|
||||
foreach ( $posts as $post ) {
|
||||
$activitypub_post = new \Activitypub\Model\Post( $post );
|
||||
$activitypub_activity = new \Activitypub\Model\Activity( 'Create', false );
|
||||
$activitypub_post = new Post( $post );
|
||||
$activitypub_activity = new Activity( 'Create', false );
|
||||
|
||||
$activitypub_activity->from_post( $activitypub_post );
|
||||
$json->orderedItems[] = $activitypub_activity->to_array(); // phpcs:ignore
|
||||
|
@ -117,7 +127,7 @@ class Outbox {
|
|||
*/
|
||||
\do_action( 'activitypub_outbox_post' );
|
||||
|
||||
$response = new \WP_REST_Response( $json, 200 );
|
||||
$response = new WP_REST_Response( $json, 200 );
|
||||
|
||||
$response->header( 'Content-Type', 'application/activity+json' );
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ class Webfinger {
|
|||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
'activitypub/1.0',
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/webfinger',
|
||||
array(
|
||||
array(
|
||||
|
|
|
@ -35,7 +35,7 @@ class Followers extends WP_List_Table {
|
|||
$page_num = $this->get_pagenum();
|
||||
$per_page = 20;
|
||||
|
||||
$follower = FollowerCollection::get_followers( \get_current_user_id(), ACTIVITYPUB_OBJECT, $per_page, ( $page_num - 1 ) * $per_page );
|
||||
$follower = FollowerCollection::get_followers( \get_current_user_id(), $per_page, ( $page_num - 1 ) * $per_page );
|
||||
$counter = FollowerCollection::count_followers( \get_current_user_id() );
|
||||
|
||||
$this->items = array();
|
||||
|
|
|
@ -3,7 +3,7 @@ namespace Activitypub\Integration;
|
|||
|
||||
class Buddypress {
|
||||
public static function init() {
|
||||
\add_filter( 'activitypub_json_author_array', array( 'Activitypub\Integration\Buddypress', 'add_user_metadata' ), 11, 2 );
|
||||
\add_filter( 'activitypub_json_author_array', array( self::class, 'add_user_metadata' ), 11, 2 );
|
||||
}
|
||||
|
||||
public static function add_user_metadata( $object, $author_id ) {
|
||||
|
|
50
integration/class-wp-sweep.php
Normal file
50
integration/class-wp-sweep.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
namespace Activitypub\Integration;
|
||||
|
||||
use Activitypub\Collection\Followers;
|
||||
|
||||
/**
|
||||
* Manages the compatibility with WP Sweep.
|
||||
*
|
||||
* @link https://wordpress.org/plugins/wp-sweep/
|
||||
* @link https://github.com/polylang/polylang/tree/master/integrations/wp-sweep
|
||||
*/
|
||||
class Wp_Sweep {
|
||||
/**
|
||||
* Setups actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function init() {
|
||||
add_filter( 'wp_sweep_excluded_taxonomies', array( self::class, 'excluded_taxonomies' ) );
|
||||
add_filter( 'wp_sweep_excluded_termids', array( self::class, 'excluded_termids' ), 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add 'activitypub-followers' to excluded taxonomies otherwise terms loose their language
|
||||
* and translation group.
|
||||
*
|
||||
* @param array $excluded_taxonomies List of taxonomies excluded from sweeping.
|
||||
*
|
||||
* @return array The list of taxonomies excluded from sweeping.
|
||||
*/
|
||||
public static function excluded_taxonomies( $excluded_taxonomies ) {
|
||||
return array_merge( $excluded_taxonomies, array( Followers::TAXONOMY ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the translation of the default taxonomy terms and our language terms to the excluded terms.
|
||||
*
|
||||
* @param array $excluded_term_ids List of term ids excluded from sweeping.
|
||||
*
|
||||
* @return array The list of term ids excluded from sweeping.
|
||||
*/
|
||||
public static function excluded_termids( $excluded_term_ids ) {
|
||||
// We got a list of excluded terms (defaults and parents). Let exclude their translations too.
|
||||
$followers = Followers::get_all_followers( array( 'fields' => 'ids' ) );
|
||||
|
||||
$excluded_term_ids = array_merge( $excluded_term_ids, $followers );
|
||||
|
||||
return array_unique( $excluded_term_ids );
|
||||
}
|
||||
}
|
10
readme.txt
10
readme.txt
|
@ -20,11 +20,12 @@ The plugin works with the following tested federated platforms, but there may be
|
|||
|
||||
* [Mastodon](https://joinmastodon.org/)
|
||||
* [Pleroma](https://pleroma.social/)
|
||||
* [Friendica](https://friendi.ca/)
|
||||
* [HubZilla](https://hubzilla.org/)
|
||||
* [friendica](https://friendi.ca/)
|
||||
* [Hubzilla](https://hubzilla.org/)
|
||||
* [Pixelfed](https://pixelfed.org/)
|
||||
* [SocialHome](https://socialhome.network/)
|
||||
* [Socialhome](https://socialhome.network/)
|
||||
* [Misskey](https://join.misskey.page/)
|
||||
* [Calckey](https://calckey.org/)
|
||||
|
||||
Here’s what that means and what you can expect.
|
||||
|
||||
|
@ -94,7 +95,7 @@ In order for webfinger to work, it must be mapped to the root directory of the U
|
|||
|
||||
Add the following to the .htaccess file in the root directory:
|
||||
|
||||
RedirectMatch "^\/\.well-known(.*)$" "\/blog\/\.well-known$1"
|
||||
RedirectMatch "^\/\.well-known/(webfinger|nodeinfo|x-nodeinfo2)(.*)$" "\/blog\/\.well-known$1$2"
|
||||
|
||||
Where 'blog' is the path to the subdirectory at which your blog resides.
|
||||
|
||||
|
@ -115,6 +116,7 @@ Project maintained on GitHub at [automattic/wordpress-activitypub](https://githu
|
|||
|
||||
= Next =
|
||||
|
||||
* Compatibility: add a new conditional, `\Activitypub\is_activitypub_request()`, to allow third-party plugins to detect ActivityPub requests.
|
||||
* Compatibility: add hooks to allow modifying images returned in ActivityPub requests.
|
||||
* Compatibility: indicate that the plugin is compatible and has been tested with the latest version of WordPress, 6.2.
|
||||
|
||||
|
|
|
@ -28,10 +28,10 @@ if ( \has_header_image() ) {
|
|||
);
|
||||
}
|
||||
|
||||
$json->inbox = \get_rest_url( null, "/activitypub/1.0/users/$author_id/inbox" );
|
||||
$json->outbox = \get_rest_url( null, "/activitypub/1.0/users/$author_id/outbox" );
|
||||
$json->followers = \get_rest_url( null, "/activitypub/1.0/users/$author_id/followers" );
|
||||
$json->following = \get_rest_url( null, "/activitypub/1.0/users/$author_id/following" );
|
||||
$json->inbox = \Activitypub\get_rest_url_by_path( sprintf( 'users/%d/inbox', $author_id ) );
|
||||
$json->outbox = \Activitypub\get_rest_url_by_path( sprintf( 'users/%d/outbox', $author_id ) );
|
||||
$json->followers = \Activitypub\get_rest_url_by_path( sprintf( 'users/%d/followers', $author_id ) );
|
||||
$json->following = \Activitypub\get_rest_url_by_path( sprintf( 'users/%d/following', $author_id ) );
|
||||
|
||||
$json->manuallyApprovesFollowers = \apply_filters( 'activitypub_json_manually_approves_followers', \__return_false() ); // phpcs:ignore
|
||||
|
||||
|
|
|
@ -27,10 +27,10 @@ if ( \has_header_image() ) {
|
|||
);
|
||||
}
|
||||
|
||||
$json->inbox = \get_rest_url( null, '/activitypub/1.0/blog/inbox' );
|
||||
$json->outbox = \get_rest_url( null, '/activitypub/1.0/blog/outbox' );
|
||||
$json->followers = \get_rest_url( null, '/activitypub/1.0/blog/followers' );
|
||||
$json->following = \get_rest_url( null, '/activitypub/1.0/blog/following' );
|
||||
$json->inbox = \Activitypub\get_rest_url_by_path( 'blog/inbox' );
|
||||
$json->outbox = \Activitypub\get_rest_url_by_path( 'blog/outbox' );
|
||||
$json->followers = \Activitypub\get_rest_url_by_path( 'blog/followers' );
|
||||
$json->following = \Activitypub\get_rest_url_by_path( 'blog/following' );
|
||||
|
||||
$json->manuallyApprovesFollowers = \apply_filters( 'activitypub_json_manually_approves_followers', \__return_false() ); // phpcs:ignore
|
||||
|
||||
|
|
|
@ -120,8 +120,8 @@
|
|||
<?php // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited ?>
|
||||
<?php foreach ( $post_types as $post_type ) { ?>
|
||||
<li>
|
||||
<input type="checkbox" id="activitypub_support_post_types" name="activitypub_support_post_types[]" value="<?php echo \esc_attr( $post_type->name ); ?>" <?php echo \checked( true, \in_array( $post_type->name, $support_post_types, true ) ); ?> />
|
||||
<label for="<?php echo \esc_attr( $post_type->name ); ?>"><?php echo \esc_html( $post_type->label ); ?></label>
|
||||
<input type="checkbox" id="activitypub_support_post_type_<?php echo \esc_attr( $post_type->name ); ?>" name="activitypub_support_post_types[]" value="<?php echo \esc_attr( $post_type->name ); ?>" <?php echo \checked( \in_array( $post_type->name, $support_post_types, true ) ); ?> />
|
||||
<label for="activitypub_support_post_type_<?php echo \esc_attr( $post_type->name ); ?>"><?php echo \esc_html( $post_type->label ); ?></label>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ul>
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
<p><?php \esc_html_e( 'ActivityPub works as is and there is no need for you to install additional plugins, nevertheless there are some plugins that extends the functionality of ActivityPub.', 'activitypub' ); ?></p>
|
||||
|
||||
<div class="activitypub-settings-accordion">
|
||||
<?php if ( ! \defined( 'FRIENDS_VERSION' ) ) : ?>
|
||||
<h4 class="activitypub-settings-accordion-heading">
|
||||
<button aria-expanded="true" class="activitypub-settings-accordion-trigger" aria-controls="activitypub-settings-accordion-block-friends-plugin" type="button">
|
||||
<span class="title"><?php \esc_html_e( 'Following Others', 'activitypub' ); ?></span>
|
||||
|
@ -58,8 +59,10 @@
|
|||
</h4>
|
||||
<div id="activitypub-settings-accordion-block-friends-plugin" class="activitypub-settings-accordion-panel plugin-card-friends">
|
||||
<p><?php \esc_html_e( 'To follow people on Mastodon or similar platforms using your own WordPress, you can use the Friends Plugin for WordPress which uses this plugin to receive posts and display them on your own WordPress, thus making your own WordPress a Fediverse instance of its own.', 'activitypub' ); ?></p>
|
||||
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=friends&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install the Friends Plugin for WordPress', 'activitypub' ); ?></a></p>
|
||||
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=friends&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install the Friends Plugin', 'activitypub' ); ?></a></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! \class_exists( 'Hum' ) ) : ?>
|
||||
<h4 class="activitypub-settings-accordion-heading">
|
||||
<button aria-expanded="false" class="activitypub-settings-accordion-trigger" aria-controls="activitypub-settings-accordion-block-activitypub-hum-plugin" type="button">
|
||||
<span class="title"><?php \esc_html_e( 'Add a URL Shortener', 'activitypub' ); ?></span>
|
||||
|
@ -68,8 +71,10 @@
|
|||
</h4>
|
||||
<div id="activitypub-settings-accordion-block-activitypub-hum-plugin" class="activitypub-settings-accordion-panel plugin-card-hum" hidden="hidden">
|
||||
<p><?php \esc_html_e( 'Hum is a personal URL shortener for WordPress, designed to provide short URLs to your personal content, both hosted on WordPress and elsewhere.', 'activitypub' ); ?></p>
|
||||
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=hum&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install Hum Plugin for WordPress', 'activitypub' ); ?></a></p>
|
||||
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=hum&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install the Hum Plugin', 'activitypub' ); ?></a></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! \class_exists( 'Webfinger' ) ) : ?>
|
||||
<h4 class="activitypub-settings-accordion-heading">
|
||||
<button aria-expanded="false" class="activitypub-settings-accordion-trigger" aria-controls="activitypub-settings-accordion-block-activitypub-webfinger-plugin" type="button">
|
||||
<span class="title"><?php \esc_html_e( 'Advanced WebFinger Support', 'activitypub' ); ?></span>
|
||||
|
@ -79,8 +84,10 @@
|
|||
<div id="activitypub-settings-accordion-block-activitypub-webfinger-plugin" class="activitypub-settings-accordion-panel plugin-card-webfinger" hidden="hidden">
|
||||
<p><?php \esc_html_e( 'WebFinger is a protocol that allows for discovery of information about people and things identified by a URI. Information about a person might be discovered via an "acct:" URI, for example, which is a URI that looks like an email address.', 'activitypub' ); ?></p>
|
||||
<p><?php \esc_html_e( 'The ActivityPub plugin comes with basic WebFinger support, if you need more configuration options and compatibility with other Fediverse/IndieWeb plugins, please install the WebFinger plugin.', 'activitypub' ); ?></p>
|
||||
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=webfinger&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install WebFinger Plugin for WordPress', 'activitypub' ); ?></a></p>
|
||||
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=webfinger&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install the WebFinger Plugin', 'activitypub' ); ?></a></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! \function_exists( 'nodeinfo_init' ) ) : ?>
|
||||
<h4 class="activitypub-settings-accordion-heading">
|
||||
<button aria-expanded="false" class="activitypub-settings-accordion-trigger" aria-controls="activitypub-settings-accordion-block-activitypub-nodeinfo-plugin" type="button">
|
||||
<span class="title"><?php \esc_html_e( 'Provide Enhanced Information about Your Blog', 'activitypub' ); ?></span>
|
||||
|
@ -90,8 +97,9 @@
|
|||
<div id="activitypub-settings-accordion-block-activitypub-nodeinfo-plugin" class="activitypub-settings-accordion-panel plugin-card-nodeinfo" hidden="hidden">
|
||||
<p><?php \esc_html_e( 'NodeInfo is an effort to create a standardized way of exposing metadata about a server running one of the distributed social networks. The two key goals are being able to get better insights into the user base of distributed social networking and the ability to build tools that allow users to choose the best fitting software and server for their needs.', 'activitypub' ); ?></p>
|
||||
<p><?php \esc_html_e( 'The ActivityPub plugin comes with a simple NodeInfo endpoint. If you need more configuration options and compatibility with other Fediverse plugins, please install the NodeInfo plugin.', 'activitypub' ); ?></p>
|
||||
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=nodeinfo&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install NodeInfo Plugin for WordPress', 'activitypub' ); ?></a></p>
|
||||
</div>
|
||||
<p><a href="<?php echo \esc_url_raw( \admin_url( 'plugin-install.php?tab=plugin-information&plugin=nodeinfo&TB_iframe=true' ) ); ?>" class="thickbox open-plugin-details-modal button install-now" target="_blank"><?php \esc_html_e( 'Install the NodeInfo Plugin', 'activitypub' ); ?></a></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
|
|
@ -22,7 +22,7 @@ class Test_Activitypub_Activity extends WP_UnitTestCase {
|
|||
$activitypub_activity = new \Activitypub\Model\Activity( 'Create' );
|
||||
$activitypub_activity->from_post( $activitypub_post );
|
||||
|
||||
$this->assertContains( \get_rest_url( null, '/activitypub/1.0/users/1/followers' ), $activitypub_activity->get_to() );
|
||||
$this->assertContains( \Activitypub\get_rest_url_by_path( 'users/1/followers' ), $activitypub_activity->get_to() );
|
||||
$this->assertContains( 'https://example.com/alex', $activitypub_activity->get_cc() );
|
||||
|
||||
remove_all_filters( 'activitypub_extract_mentions' );
|
||||
|
|
|
@ -58,6 +58,13 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
|||
|
||||
$this->assertEquals( 3, \count( $db_followers ) );
|
||||
|
||||
$db_followers = array_map(
|
||||
function( $item ) {
|
||||
return $item->get_actor();
|
||||
},
|
||||
$db_followers
|
||||
);
|
||||
|
||||
$this->assertSame( array( 'https://example.com/author/jon', 'https://example.org/author/doe', 'http://sally.example.org' ), $db_followers );
|
||||
}
|
||||
|
||||
|
@ -90,6 +97,60 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
|||
$this->assertNull( $follower );
|
||||
}
|
||||
|
||||
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 = new \Activitypub\Model\Follower( 'https://example.com/author/jon' );
|
||||
|
||||
update_term_meta( $follower->get_id(), 'updated_at', \time() - 804800 );
|
||||
|
||||
$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 = new \Activitypub\Model\Follower( 'http://sally.example.org' );
|
||||
|
||||
for ( $i = 1; $i <= 15; $i++ ) {
|
||||
add_term_meta( $follower->get_id(), 'errors', 'error ' . $i );
|
||||
}
|
||||
|
||||
$follower = new \Activitypub\Model\Follower( '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 = new \Activitypub\Model\Follower( 'http://sally.example.org' );
|
||||
$count = $follower->count_errors();
|
||||
|
||||
$followers = \Activitypub\Collection\Followers::get_faulty_followers();
|
||||
|
||||
$this->assertEquals( 0, count( $followers ) );
|
||||
}
|
||||
|
||||
|
||||
public static function http_request_host_is_external( $in, $host ) {
|
||||
if ( in_array( $host, array( 'example.com', 'example.org' ), true ) ) {
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue