updated plugin ActivityPub
version 3.3.3
This commit is contained in:
@ -1,18 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* ActivityPub Actors REST-Class
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_Error;
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
use Activitypub\Webfinger;
|
||||
use Activitypub\Activity\Activity;
|
||||
use Activitypub\Collection\Users as User_Collection;
|
||||
|
||||
use function Activitypub\is_activitypub_request;
|
||||
|
||||
/**
|
||||
* ActivityPub Actors REST-Class
|
||||
* ActivityPub Actors REST-Class.
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*
|
||||
@ -20,14 +24,14 @@ use function Activitypub\is_activitypub_request;
|
||||
*/
|
||||
class Actors {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register routes
|
||||
* Register routes.
|
||||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
@ -65,9 +69,9 @@ class Actors {
|
||||
/**
|
||||
* Handle GET request
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
* @return WP_REST_Response|\WP_Error The response object or WP_Error.
|
||||
*/
|
||||
public static function get( $request ) {
|
||||
$user_id = $request->get_param( 'user_id' );
|
||||
@ -77,14 +81,17 @@ class Actors {
|
||||
return $user;
|
||||
}
|
||||
|
||||
// redirect to canonical URL if it is not an ActivityPub request
|
||||
$link_header = sprintf( '<%1$s>; rel="alternate"; type="application/activity+json"', $user->get_id() );
|
||||
|
||||
// Redirect to canonical URL if it is not an ActivityPub request.
|
||||
if ( ! is_activitypub_request() ) {
|
||||
header( 'Link: ' . $link_header );
|
||||
header( 'Location: ' . $user->get_canonical_url(), true, 301 );
|
||||
exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Action triggerd prior to the ActivityPub profile being created and sent to the client
|
||||
/**
|
||||
* Action triggered prior to the ActivityPub profile being created and sent to the client.
|
||||
*/
|
||||
\do_action( 'activitypub_rest_users_pre' );
|
||||
|
||||
@ -92,17 +99,18 @@ class Actors {
|
||||
|
||||
$rest_response = new WP_REST_Response( $json, 200 );
|
||||
$rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) );
|
||||
$rest_response->header( 'Link', $link_header );
|
||||
|
||||
return $rest_response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Endpoint for remote follow UI/Block
|
||||
* Endpoint for remote follow UI/Block.
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return void|string The URL to the remote follow page
|
||||
* @return WP_REST_Response|\WP_Error The response object or WP_Error.
|
||||
*/
|
||||
public static function remote_follow_get( WP_REST_Request $request ) {
|
||||
$resource = $request->get_param( 'resource' );
|
||||
@ -123,15 +131,18 @@ class Actors {
|
||||
$url = str_replace( '{uri}', $resource, $template );
|
||||
|
||||
return new WP_REST_Response(
|
||||
array( 'url' => $url, 'template' => $template ),
|
||||
array(
|
||||
'url' => $url,
|
||||
'template' => $template,
|
||||
),
|
||||
200
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The supported parameters
|
||||
* The supported parameters.
|
||||
*
|
||||
* @return array list of parameters
|
||||
* @return array List of parameters,
|
||||
*/
|
||||
public static function request_parameters() {
|
||||
$params = array();
|
||||
|
@ -1,4 +1,10 @@
|
||||
<?php
|
||||
/**
|
||||
* Collections REST-Class file.
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_REST_Server;
|
||||
@ -6,14 +12,17 @@ use WP_REST_Response;
|
||||
use Activitypub\Activity\Actor;
|
||||
use Activitypub\Activity\Base_Object;
|
||||
use Activitypub\Collection\Users as User_Collection;
|
||||
use Activitypub\Collection\Replies;
|
||||
|
||||
use Activitypub\Transformer\Factory;
|
||||
use WP_Error;
|
||||
|
||||
use function Activitypub\esc_hashtag;
|
||||
use function Activitypub\is_single_user;
|
||||
use function Activitypub\get_rest_url_by_path;
|
||||
|
||||
/**
|
||||
* ActivityPub Collections REST-Class
|
||||
* ActivityPub Collections REST-Class.
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*
|
||||
@ -22,14 +31,14 @@ use function Activitypub\get_rest_url_by_path;
|
||||
*/
|
||||
class Collection {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register routes
|
||||
* Register routes.
|
||||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
@ -69,14 +78,81 @@ class Collection {
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
\register_rest_route(
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/(?P<type>[\w\-\.]+)s/(?P<id>[\w\-\.]+)/replies',
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( self::class, 'replies_get' ),
|
||||
'args' => self::request_parameters_for_replies(),
|
||||
'permission_callback' => '__return_true',
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The endpoint for replies collections.
|
||||
*
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response|\WP_Error The response object or WP_Error.
|
||||
*/
|
||||
public static function replies_get( $request ) {
|
||||
$type = $request->get_param( 'type' );
|
||||
|
||||
// Get the WordPress object of that "owns" the requested replies.
|
||||
switch ( $type ) {
|
||||
case 'comment':
|
||||
$wp_object = \get_comment( $request->get_param( 'id' ) );
|
||||
break;
|
||||
case 'post':
|
||||
default:
|
||||
$wp_object = \get_post( $request->get_param( 'id' ) );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! isset( $wp_object ) || is_wp_error( $wp_object ) ) {
|
||||
return new WP_Error(
|
||||
'activitypub_replies_collection_does_not_exist',
|
||||
\sprintf(
|
||||
// translators: %s: The type (post, comment, etc.) for which no replies collection exists.
|
||||
\__( 'No reply collection exists for the type %s.', 'activitypub' ),
|
||||
$type
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$page = intval( $request->get_param( 'page' ) );
|
||||
|
||||
// If the request parameter page is present get the CollectionPage otherwise the replies collection.
|
||||
if ( isset( $page ) ) {
|
||||
$response = Replies::get_collection_page( $wp_object, $page );
|
||||
} else {
|
||||
$response = Replies::get_collection( $wp_object );
|
||||
}
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
// Add ActivityPub Context.
|
||||
$response = array_merge(
|
||||
array( '@context' => Base_Object::JSON_LD_CONTEXT ),
|
||||
$response
|
||||
);
|
||||
|
||||
return new WP_REST_Response( $response, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* The Featured Tags endpoint
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response The response object.
|
||||
* @return WP_REST_Response|\WP_Error The response object or WP_Error.
|
||||
*/
|
||||
public static function tags_get( $request ) {
|
||||
$user_id = $request->get_param( 'user_id' );
|
||||
@ -126,9 +202,9 @@ class Collection {
|
||||
/**
|
||||
* Featured posts endpoint
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response The response object.
|
||||
* @return WP_REST_Response|\WP_Error The response object or WP_Error.
|
||||
*/
|
||||
public static function featured_get( $request ) {
|
||||
$user_id = $request->get_param( 'user_id' );
|
||||
@ -184,13 +260,11 @@ class Collection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Moderators endpoint
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
* Moderators endpoint.
|
||||
*
|
||||
* @return WP_REST_Response The response object.
|
||||
*/
|
||||
public static function moderators_get( $request ) {
|
||||
public static function moderators_get() {
|
||||
$response = array(
|
||||
'@context' => Actor::JSON_LD_CONTEXT,
|
||||
'id' => get_rest_url_by_path( 'collections/moderators' ),
|
||||
@ -211,16 +285,38 @@ class Collection {
|
||||
}
|
||||
|
||||
/**
|
||||
* The supported parameters
|
||||
* The supported parameters.
|
||||
*
|
||||
* @return array list of parameters
|
||||
* @return array List of parameters.
|
||||
*/
|
||||
public static function request_parameters() {
|
||||
$params = array();
|
||||
|
||||
$params['user_id'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'type' => 'string',
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* The supported parameters.
|
||||
*
|
||||
* @return array list of parameters.
|
||||
*/
|
||||
public static function request_parameters_for_replies() {
|
||||
$params = array();
|
||||
|
||||
$params['type'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'enum' => array( 'post', 'comment' ),
|
||||
);
|
||||
|
||||
$params['id'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
);
|
||||
|
||||
return $params;
|
||||
|
@ -1,4 +1,10 @@
|
||||
<?php
|
||||
/**
|
||||
* Comment REST-Class file.
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_Error;
|
||||
@ -9,7 +15,7 @@ use Activitypub\Comment as Comment_Utils;
|
||||
use Activitypub\Webfinger as Webfinger_Utils;
|
||||
|
||||
/**
|
||||
* ActivityPub Followers REST-Class
|
||||
* ActivityPub Followers REST-Class.
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*
|
||||
@ -17,14 +23,14 @@ use Activitypub\Webfinger as Webfinger_Utils;
|
||||
*/
|
||||
class Comment {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register routes
|
||||
* Register routes.
|
||||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
@ -47,11 +53,11 @@ class Comment {
|
||||
}
|
||||
|
||||
/**
|
||||
* Endpoint for remote follow UI/Block
|
||||
* Endpoint for remote follow UI/Block.
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return void|string The URL to the remote follow page
|
||||
* @return array|string|WP_Error|WP_REST_Response The URL to the remote follow page or an error.
|
||||
*/
|
||||
public static function remote_reply_get( WP_REST_Request $request ) {
|
||||
$resource = $request->get_param( 'resource' );
|
||||
@ -75,20 +81,19 @@ class Comment {
|
||||
return $template;
|
||||
}
|
||||
|
||||
$comment_meta = \get_comment_meta( $comment_id );
|
||||
$resource = Comment_Utils::get_source_id( $comment_id );
|
||||
|
||||
if ( ! empty( $comment_meta['source_id'][0] ) ) {
|
||||
$resource = $comment_meta['source_id'][0];
|
||||
} elseif ( ! empty( $comment_meta['source_url'][0] ) ) {
|
||||
$resource = $comment_meta['source_url'][0];
|
||||
} else {
|
||||
if ( ! $resource ) {
|
||||
$resource = Comment_Utils::generate_id( $comment );
|
||||
}
|
||||
|
||||
$url = str_replace( '{uri}', $resource, $template );
|
||||
|
||||
return new WP_REST_Response(
|
||||
array( 'url' => $url, 'template' => $template ),
|
||||
array(
|
||||
'url' => $url,
|
||||
'template' => $template,
|
||||
),
|
||||
200
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* Followers REST-Class file.
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_Error;
|
||||
use stdClass;
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Response;
|
||||
@ -12,7 +17,7 @@ use function Activitypub\get_rest_url_by_path;
|
||||
use function Activitypub\get_masked_wp_version;
|
||||
|
||||
/**
|
||||
* ActivityPub Followers REST-Class
|
||||
* ActivityPub Followers REST-Class.
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*
|
||||
@ -20,14 +25,14 @@ use function Activitypub\get_masked_wp_version;
|
||||
*/
|
||||
class Followers {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register routes
|
||||
* Register routes.
|
||||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
@ -47,9 +52,9 @@ class Followers {
|
||||
/**
|
||||
* Handle GET request
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
* @return WP_REST_Response|\WP_Error The response object or WP_Error.
|
||||
*/
|
||||
public static function get( $request ) {
|
||||
$user_id = $request->get_param( 'user_id' );
|
||||
@ -64,36 +69,34 @@ class Followers {
|
||||
$page = (int) $request->get_param( 'page' );
|
||||
$context = $request->get_param( 'context' );
|
||||
|
||||
/*
|
||||
* Action triggerd prior to the ActivityPub profile being created and sent to the client
|
||||
/**
|
||||
* Action triggered prior to the ActivityPub profile being created and sent to the client
|
||||
*/
|
||||
\do_action( 'activitypub_rest_followers_pre' );
|
||||
|
||||
$data = Follower_Collection::get_followers_with_count( $user_id, $per_page, $page, array( 'order' => ucwords( $order ) ) );
|
||||
$json = new stdClass();
|
||||
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$json->{'@context'} = \Activitypub\get_context();
|
||||
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/followers', $user->get__id() ) );
|
||||
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
|
||||
$json->actor = $user->get_id();
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
$json->totalItems = $data['total'];
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/followers', $user->get__id() ) );
|
||||
|
||||
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/followers', $user->get__id() ) );
|
||||
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
|
||||
$json->actor = $user->get_id();
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
$json->first = \add_query_arg( 'page', 1, $json->partOf );
|
||||
$json->last = \add_query_arg( 'page', \ceil( $json->totalItems / $per_page ), $json->partOf );
|
||||
|
||||
$json->totalItems = $data['total']; // phpcs:ignore
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/followers', $user->get__id() ) ); // phpcs:ignore
|
||||
|
||||
$json->first = \add_query_arg( 'page', 1, $json->partOf ); // phpcs:ignore
|
||||
$json->last = \add_query_arg( 'page', \ceil ( $json->totalItems / $per_page ), $json->partOf ); // phpcs:ignore
|
||||
|
||||
if ( $page && ( ( \ceil ( $json->totalItems / $per_page ) ) > $page ) ) { // phpcs:ignore
|
||||
$json->next = \add_query_arg( 'page', $page + 1, $json->partOf ); // phpcs:ignore
|
||||
if ( $page && ( ( \ceil( $json->totalItems / $per_page ) ) > $page ) ) {
|
||||
$json->next = \add_query_arg( 'page', $page + 1, $json->partOf );
|
||||
}
|
||||
|
||||
if ( $page && ( $page > 1 ) ) { // phpcs:ignore
|
||||
$json->prev = \add_query_arg( 'page', $page - 1, $json->partOf ); // phpcs:ignore
|
||||
if ( $page && ( $page > 1 ) ) {
|
||||
$json->prev = \add_query_arg( 'page', $page - 1, $json->partOf );
|
||||
}
|
||||
|
||||
// phpcs:ignore
|
||||
$json->orderedItems = array_map(
|
||||
function ( $item ) use ( $context ) {
|
||||
if ( 'full' === $context ) {
|
||||
@ -103,6 +106,7 @@ class Followers {
|
||||
},
|
||||
$data['followers']
|
||||
);
|
||||
// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
|
||||
$rest_response = new WP_REST_Response( $json, 200 );
|
||||
$rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) );
|
||||
@ -111,20 +115,20 @@ class Followers {
|
||||
}
|
||||
|
||||
/**
|
||||
* The supported parameters
|
||||
* The supported parameters.
|
||||
*
|
||||
* @return array list of parameters
|
||||
* @return array List of parameters.
|
||||
*/
|
||||
public static function request_parameters() {
|
||||
$params = array();
|
||||
|
||||
$params['page'] = array(
|
||||
'type' => 'integer',
|
||||
'type' => 'integer',
|
||||
'default' => 1,
|
||||
);
|
||||
|
||||
$params['per_page'] = array(
|
||||
'type' => 'integer',
|
||||
'type' => 'integer',
|
||||
'default' => 20,
|
||||
);
|
||||
|
||||
@ -136,13 +140,13 @@ class Followers {
|
||||
|
||||
$params['user_id'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'type' => 'string',
|
||||
);
|
||||
|
||||
$params['context'] = array(
|
||||
'type' => 'string',
|
||||
'type' => 'string',
|
||||
'default' => 'simple',
|
||||
'enum' => array( 'simple', 'full' ),
|
||||
'enum' => array( 'simple', 'full' ),
|
||||
);
|
||||
|
||||
return $params;
|
||||
|
@ -1,4 +1,10 @@
|
||||
<?php
|
||||
/**
|
||||
* ActivityPub Following REST-Class file.
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_REST_Response;
|
||||
@ -9,7 +15,7 @@ use function Activitypub\get_rest_url_by_path;
|
||||
use function Activitypub\get_masked_wp_version;
|
||||
|
||||
/**
|
||||
* ActivityPub Following REST-Class
|
||||
* ActivityPub Following REST-Class.
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*
|
||||
@ -17,7 +23,7 @@ use function Activitypub\get_masked_wp_version;
|
||||
*/
|
||||
class Following {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
@ -46,9 +52,9 @@ class Following {
|
||||
/**
|
||||
* Handle GET request
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
* @return WP_REST_Response|\WP_Error The response object or WP_Error.
|
||||
*/
|
||||
public static function get( $request ) {
|
||||
$user_id = $request->get_param( 'user_id' );
|
||||
@ -58,8 +64,8 @@ class Following {
|
||||
return $user;
|
||||
}
|
||||
|
||||
/*
|
||||
* Action triggerd prior to the ActivityPub profile being created and sent to the client
|
||||
/**
|
||||
* Action triggered prior to the ActivityPub profile being created and sent to the client.
|
||||
*/
|
||||
\do_action( 'activitypub_rest_following_pre' );
|
||||
|
||||
@ -67,19 +73,25 @@ class Following {
|
||||
|
||||
$json->{'@context'} = \Activitypub\get_context();
|
||||
|
||||
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/following', $user->get__id() ) );
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/following', $user->get__id() ) );
|
||||
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
|
||||
$json->actor = $user->get_id();
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
$json->actor = $user->get_id();
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/following', $user->get__id() ) );
|
||||
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/following', $user->get__id() ) ); // phpcs:ignore
|
||||
/**
|
||||
* Filter the list of following urls.
|
||||
*
|
||||
* @param array $items The array of following urls.
|
||||
* @param \Activitypub\Model\User $user The user object.
|
||||
*/
|
||||
$items = apply_filters( 'activitypub_rest_following', array(), $user );
|
||||
|
||||
$items = apply_filters( 'activitypub_rest_following', array(), $user ); // phpcs:ignore
|
||||
|
||||
$json->totalItems = is_countable( $items ) ? count( $items ) : 0; // phpcs:ignore
|
||||
$json->orderedItems = $items; // phpcs:ignore
|
||||
|
||||
$json->first = $json->partOf; // phpcs:ignore
|
||||
$json->totalItems = is_countable( $items ) ? count( $items ) : 0;
|
||||
$json->orderedItems = $items;
|
||||
$json->first = $json->partOf;
|
||||
// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
|
||||
$rest_response = new WP_REST_Response( $json, 200 );
|
||||
$rest_response->header( 'Content-Type', 'application/activity+json; charset=' . get_option( 'blog_charset' ) );
|
||||
@ -88,9 +100,9 @@ class Following {
|
||||
}
|
||||
|
||||
/**
|
||||
* The supported parameters
|
||||
* The supported parameters.
|
||||
*
|
||||
* @return array list of parameters
|
||||
* @return array List of parameters.
|
||||
*/
|
||||
public static function request_parameters() {
|
||||
$params = array();
|
||||
@ -101,7 +113,7 @@ class Following {
|
||||
|
||||
$params['user_id'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'type' => 'string',
|
||||
);
|
||||
|
||||
return $params;
|
||||
@ -111,22 +123,22 @@ class Following {
|
||||
* Add the Blog Authors to the following list of the Blog Actor
|
||||
* if Blog not in single mode.
|
||||
*
|
||||
* @param array $array The array of following urls.
|
||||
* @param User $user The user object.
|
||||
* @param array $follow_list The array of following urls.
|
||||
* @param \Activitypub\Model\User $user The user object.
|
||||
*
|
||||
* @return array The array of following urls.
|
||||
*/
|
||||
public static function default_following( $array, $user ) {
|
||||
public static function default_following( $follow_list, $user ) {
|
||||
if ( 0 !== $user->get__id() || is_single_user() ) {
|
||||
return $array;
|
||||
return $follow_list;
|
||||
}
|
||||
|
||||
$users = User_Collection::get_collection();
|
||||
|
||||
foreach ( $users as $user ) {
|
||||
$array[] = $user->get_url();
|
||||
$follow_list[] = $user->get_url();
|
||||
}
|
||||
|
||||
return $array;
|
||||
return $follow_list;
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* Inbox REST-Class file.
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_Error;
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Response;
|
||||
use Activitypub\Activity\Activity;
|
||||
use Activitypub\Collection\Users as User_Collection;
|
||||
|
||||
use function Activitypub\get_context;
|
||||
use function Activitypub\object_to_uri;
|
||||
use function Activitypub\url_to_authorid;
|
||||
use function Activitypub\get_rest_url_by_path;
|
||||
use function Activitypub\get_masked_wp_version;
|
||||
use function Activitypub\extract_recipients_from_activity;
|
||||
|
||||
/**
|
||||
* ActivityPub Inbox REST-Class
|
||||
* ActivityPub Inbox REST-Class.
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*
|
||||
@ -23,14 +27,14 @@ use function Activitypub\extract_recipients_from_activity;
|
||||
*/
|
||||
class Inbox {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register routes
|
||||
* Register routes.
|
||||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
@ -67,10 +71,10 @@ class Inbox {
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the user-inbox
|
||||
* Renders the user-inbox.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_REST_Response
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
* @return WP_REST_Response|\WP_Error The response object or WP_Error.
|
||||
*/
|
||||
public static function user_inbox_get( $request ) {
|
||||
$user_id = $request->get_param( 'user_id' );
|
||||
@ -80,29 +84,33 @@ class Inbox {
|
||||
return $user;
|
||||
}
|
||||
|
||||
$page = $request->get_param( 'page', 0 );
|
||||
|
||||
/*
|
||||
* Action triggerd prior to the ActivityPub profile being created and sent to the client
|
||||
/**
|
||||
* Action triggered prior to the ActivityPub profile being created and sent to the client.
|
||||
*/
|
||||
\do_action( 'activitypub_rest_inbox_pre' );
|
||||
|
||||
$json = new \stdClass();
|
||||
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$json->{'@context'} = get_context();
|
||||
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/inbox', $user->get__id() ) );
|
||||
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/inbox', $user->get__id() ) ); // phpcs:ignore
|
||||
$json->totalItems = 0; // phpcs:ignore
|
||||
$json->orderedItems = array(); // phpcs:ignore
|
||||
$json->first = $json->partOf; // phpcs:ignore
|
||||
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/inbox', $user->get__id() ) );
|
||||
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/inbox', $user->get__id() ) );
|
||||
$json->totalItems = 0;
|
||||
$json->orderedItems = array();
|
||||
$json->first = $json->partOf;
|
||||
// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
|
||||
// filter output
|
||||
/**
|
||||
* Filter the ActivityPub inbox array.
|
||||
*
|
||||
* @param array $json The ActivityPub inbox array.
|
||||
*/
|
||||
$json = \apply_filters( 'activitypub_rest_inbox_array', $json );
|
||||
|
||||
/*
|
||||
* Action triggerd after the ActivityPub profile has been created and sent to the client
|
||||
/**
|
||||
* Action triggered after the ActivityPub profile has been created and sent to the client.
|
||||
*/
|
||||
\do_action( 'activitypub_inbox_post' );
|
||||
|
||||
@ -113,11 +121,11 @@ class Inbox {
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles user-inbox requests
|
||||
* Handles user-inbox requests.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
* @return WP_REST_Response|\WP_Error The response object or WP_Error.
|
||||
*/
|
||||
public static function user_inbox_post( $request ) {
|
||||
$user_id = $request->get_param( 'user_id' );
|
||||
@ -132,7 +140,23 @@ class Inbox {
|
||||
$type = $request->get_param( 'type' );
|
||||
$type = \strtolower( $type );
|
||||
|
||||
/**
|
||||
* ActivityPub inbox action.
|
||||
*
|
||||
* @param array $data The data array.
|
||||
* @param int|null $user_id The user ID.
|
||||
* @param string $type The type of the activity.
|
||||
* @param Activity $activity The Activity object.
|
||||
*/
|
||||
\do_action( 'activitypub_inbox', $data, $user->get__id(), $type, $activity );
|
||||
|
||||
/**
|
||||
* ActivityPub inbox action for specific activity types.
|
||||
*
|
||||
* @param array $data The data array.
|
||||
* @param int|null $user_id The user ID.
|
||||
* @param Activity $activity The Activity object.
|
||||
*/
|
||||
\do_action( "activitypub_inbox_{$type}", $data, $user->get__id(), $activity );
|
||||
|
||||
$rest_response = new WP_REST_Response( array(), 202 );
|
||||
@ -142,9 +166,9 @@ class Inbox {
|
||||
}
|
||||
|
||||
/**
|
||||
* The shared inbox
|
||||
* The shared inbox.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
@ -154,7 +178,23 @@ class Inbox {
|
||||
$type = $request->get_param( 'type' );
|
||||
$type = \strtolower( $type );
|
||||
|
||||
/**
|
||||
* ActivityPub inbox action.
|
||||
*
|
||||
* @param array $data The data array.
|
||||
* @param int|null $user_id The user ID.
|
||||
* @param string $type The type of the activity.
|
||||
* @param Activity $activity The Activity object.
|
||||
*/
|
||||
\do_action( 'activitypub_inbox', $data, null, $type, $activity );
|
||||
|
||||
/**
|
||||
* ActivityPub inbox action for specific activity types.
|
||||
*
|
||||
* @param array $data The data array.
|
||||
* @param int|null $user_id The user ID.
|
||||
* @param Activity $activity The Activity object.
|
||||
*/
|
||||
\do_action( "activitypub_inbox_{$type}", $data, null, $activity );
|
||||
|
||||
$rest_response = new WP_REST_Response( array(), 202 );
|
||||
@ -164,9 +204,9 @@ class Inbox {
|
||||
}
|
||||
|
||||
/**
|
||||
* The supported parameters
|
||||
* The supported parameters.
|
||||
*
|
||||
* @return array list of parameters
|
||||
* @return array List of parameters.
|
||||
*/
|
||||
public static function user_inbox_get_parameters() {
|
||||
$params = array();
|
||||
@ -177,100 +217,68 @@ class Inbox {
|
||||
|
||||
$params['user_id'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'type' => 'string',
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* The supported parameters
|
||||
* The supported parameters.
|
||||
*
|
||||
* @return array list of parameters
|
||||
* @return array List of parameters.
|
||||
*/
|
||||
public static function user_inbox_post_parameters() {
|
||||
$params = array();
|
||||
|
||||
$params['page'] = array(
|
||||
'type' => 'integer',
|
||||
);
|
||||
|
||||
$params['user_id'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'type' => 'string',
|
||||
);
|
||||
|
||||
$params['id'] = array(
|
||||
'required' => true,
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'esc_url_raw',
|
||||
);
|
||||
|
||||
$params['actor'] = array(
|
||||
'required' => true,
|
||||
'sanitize_callback' => function ( $param, $request, $key ) {
|
||||
return object_to_uri( $param );
|
||||
},
|
||||
'required' => true,
|
||||
'sanitize_callback' => '\Activitypub\object_to_uri',
|
||||
);
|
||||
|
||||
$params['type'] = array(
|
||||
'required' => true,
|
||||
//'type' => 'enum',
|
||||
//'enum' => array( 'Create' ),
|
||||
//'sanitize_callback' => function ( $param, $request, $key ) {
|
||||
// return \strtolower( $param );
|
||||
//},
|
||||
);
|
||||
|
||||
$params['object'] = array(
|
||||
'required' => true,
|
||||
'required' => true,
|
||||
'validate_callback' => function ( $param, $request, $key ) {
|
||||
/**
|
||||
* Filter the ActivityPub object validation.
|
||||
*
|
||||
* @param bool $validate The validation result.
|
||||
* @param array $param The object data.
|
||||
* @param object $request The request object.
|
||||
* @param string $key The key.
|
||||
*/
|
||||
return apply_filters( 'activitypub_validate_object', true, $param, $request, $key );
|
||||
},
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* The supported parameters
|
||||
* The supported parameters.
|
||||
*
|
||||
* @return array list of parameters
|
||||
* @return array List of parameters.
|
||||
*/
|
||||
public static function shared_inbox_post_parameters() {
|
||||
$params = array();
|
||||
|
||||
$params['page'] = array(
|
||||
'type' => 'integer',
|
||||
);
|
||||
|
||||
$params['id'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'esc_url_raw',
|
||||
);
|
||||
|
||||
$params['actor'] = array(
|
||||
'required' => true,
|
||||
//'type' => array( 'object', 'string' ),
|
||||
'sanitize_callback' => function ( $param, $request, $key ) {
|
||||
return object_to_uri( $param );
|
||||
},
|
||||
);
|
||||
|
||||
$params['type'] = array(
|
||||
'required' => true,
|
||||
//'type' => 'enum',
|
||||
//'enum' => array( 'Create' ),
|
||||
//'sanitize_callback' => function ( $param, $request, $key ) {
|
||||
// return \strtolower( $param );
|
||||
//},
|
||||
);
|
||||
|
||||
$params['object'] = array(
|
||||
'required' => true,
|
||||
//'type' => 'object',
|
||||
);
|
||||
$params = self::user_inbox_post_parameters();
|
||||
|
||||
$params['to'] = array(
|
||||
'required' => false,
|
||||
'sanitize_callback' => function ( $param, $request, $key ) {
|
||||
'required' => false,
|
||||
'sanitize_callback' => function ( $param ) {
|
||||
if ( \is_string( $param ) ) {
|
||||
$param = array( $param );
|
||||
}
|
||||
@ -280,7 +288,7 @@ class Inbox {
|
||||
);
|
||||
|
||||
$params['cc'] = array(
|
||||
'sanitize_callback' => function ( $param, $request, $key ) {
|
||||
'sanitize_callback' => function ( $param ) {
|
||||
if ( \is_string( $param ) ) {
|
||||
$param = array( $param );
|
||||
}
|
||||
@ -290,7 +298,7 @@ class Inbox {
|
||||
);
|
||||
|
||||
$params['bcc'] = array(
|
||||
'sanitize_callback' => function ( $param, $request, $key ) {
|
||||
'sanitize_callback' => function ( $param ) {
|
||||
if ( \is_string( $param ) ) {
|
||||
$param = array( $param );
|
||||
}
|
||||
@ -303,15 +311,15 @@ class Inbox {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local user recipients
|
||||
* Get local user recipients.
|
||||
*
|
||||
* @param array $data
|
||||
* @param array $data The data array.
|
||||
*
|
||||
* @return array The list of local users
|
||||
* @return array The list of local users.
|
||||
*/
|
||||
public static function get_recipients( $data ) {
|
||||
$recipients = extract_recipients_from_activity( $data );
|
||||
$users = array();
|
||||
$users = array();
|
||||
|
||||
foreach ( $recipients as $recipient ) {
|
||||
$user_id = url_to_authorid( $recipient );
|
||||
|
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
/**
|
||||
* ActivityPub Interaction REST-Class file.
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_REST_Response;
|
||||
use Activitypub\Http;
|
||||
|
||||
/**
|
||||
* Interaction class.
|
||||
*/
|
||||
class Interaction {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register routes
|
||||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/interactions',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'callback' => array( self::class, 'get' ),
|
||||
'permission_callback' => '__return_true',
|
||||
'args' => array(
|
||||
'uri' => array(
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
'sanitize_callback' => 'esc_url',
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle GET request.
|
||||
*
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response Redirect to the editor or die.
|
||||
*/
|
||||
public static function get( $request ) {
|
||||
$uri = $request->get_param( 'uri' );
|
||||
$redirect_url = null;
|
||||
$object = Http::get_remote_object( $uri );
|
||||
|
||||
if (
|
||||
\is_wp_error( $object ) ||
|
||||
! isset( $object['type'] )
|
||||
) {
|
||||
\wp_die(
|
||||
\esc_html__(
|
||||
'The URL is not supported!',
|
||||
'activitypub'
|
||||
),
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $object['url'] ) ) {
|
||||
$uri = \esc_url( $object['url'] );
|
||||
}
|
||||
|
||||
switch ( $object['type'] ) {
|
||||
case 'Group':
|
||||
case 'Person':
|
||||
case 'Service':
|
||||
case 'Application':
|
||||
case 'Organization':
|
||||
$redirect_url = \apply_filters( 'activitypub_interactions_follow_url', $redirect_url, $uri, $object );
|
||||
break;
|
||||
default:
|
||||
$redirect_url = \admin_url( 'post-new.php?in_reply_to=' . $uri );
|
||||
$redirect_url = \apply_filters( 'activitypub_interactions_reply_url', $redirect_url, $uri, $object );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the redirect URL.
|
||||
*
|
||||
* @param string $redirect_url The URL to redirect to.
|
||||
* @param string $uri The URI of the object.
|
||||
* @param array $object The object.
|
||||
*/
|
||||
$redirect_url = \apply_filters( 'activitypub_interactions_url', $redirect_url, $uri, $object );
|
||||
|
||||
// Check if hook is implemented.
|
||||
if ( ! $redirect_url ) {
|
||||
\wp_die(
|
||||
esc_html__(
|
||||
'This Interaction type is not supported yet!',
|
||||
'activitypub'
|
||||
),
|
||||
400
|
||||
);
|
||||
}
|
||||
|
||||
return new WP_REST_Response(
|
||||
null,
|
||||
302,
|
||||
array(
|
||||
'Location' => \esc_url( $redirect_url ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,4 +1,10 @@
|
||||
<?php
|
||||
/**
|
||||
* NodeInfo REST-Class file.
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_REST_Response;
|
||||
@ -9,7 +15,7 @@ use function Activitypub\get_rest_url_by_path;
|
||||
use function Activitypub\get_masked_wp_version;
|
||||
|
||||
/**
|
||||
* ActivityPub NodeInfo REST-Class
|
||||
* ActivityPub NodeInfo REST-Class.
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*
|
||||
@ -17,7 +23,7 @@ use function Activitypub\get_masked_wp_version;
|
||||
*/
|
||||
class Nodeinfo {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
@ -65,97 +71,93 @@ class Nodeinfo {
|
||||
}
|
||||
|
||||
/**
|
||||
* Render NodeInfo file
|
||||
* Render NodeInfo file.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
* @return WP_REST_Response The JSON profile of the NodeInfo.
|
||||
*/
|
||||
public static function nodeinfo( $request ) {
|
||||
/*
|
||||
* Action triggerd prior to the ActivityPub profile being created and sent to the client
|
||||
public static function nodeinfo() {
|
||||
/**
|
||||
* Action triggered prior to the ActivityPub profile being created and sent to the client.
|
||||
*/
|
||||
\do_action( 'activitypub_rest_nodeinfo_pre' );
|
||||
|
||||
$nodeinfo = array();
|
||||
|
||||
$nodeinfo['version'] = '2.0';
|
||||
$nodeinfo['version'] = '2.0';
|
||||
$nodeinfo['software'] = array(
|
||||
'name' => 'wordpress',
|
||||
'name' => 'wordpress',
|
||||
'version' => get_masked_wp_version(),
|
||||
);
|
||||
|
||||
$posts = \wp_count_posts();
|
||||
$posts = \wp_count_posts();
|
||||
$comments = \wp_count_comments();
|
||||
|
||||
$nodeinfo['usage'] = array(
|
||||
'users' => array(
|
||||
'users' => array(
|
||||
'total' => get_total_users(),
|
||||
'activeMonth' => get_active_users( '1 month ago' ),
|
||||
'activeHalfyear' => get_active_users( '6 month ago' ),
|
||||
),
|
||||
'localPosts' => (int) $posts->publish,
|
||||
'localPosts' => (int) $posts->publish,
|
||||
'localComments' => (int) $comments->approved,
|
||||
);
|
||||
|
||||
$nodeinfo['openRegistrations'] = false;
|
||||
$nodeinfo['protocols'] = array( 'activitypub' );
|
||||
$nodeinfo['protocols'] = array( 'activitypub' );
|
||||
|
||||
$nodeinfo['services'] = array(
|
||||
'inbound' => array(),
|
||||
'inbound' => array(),
|
||||
'outbound' => array(),
|
||||
);
|
||||
|
||||
$nodeinfo['metadata'] = array(
|
||||
'nodeName' => \get_bloginfo( 'name' ),
|
||||
'nodeName' => \get_bloginfo( 'name' ),
|
||||
'nodeDescription' => \get_bloginfo( 'description' ),
|
||||
'nodeIcon' => \get_site_icon_url(),
|
||||
'nodeIcon' => \get_site_icon_url(),
|
||||
);
|
||||
|
||||
return new WP_REST_Response( $nodeinfo, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render NodeInfo file
|
||||
* Render NodeInfo file.
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
* @return WP_REST_Response The JSON profile of the NodeInfo.
|
||||
*/
|
||||
public static function nodeinfo2( $request ) {
|
||||
/*
|
||||
* Action triggerd prior to the ActivityPub profile being created and sent to the client
|
||||
public static function nodeinfo2() {
|
||||
/**
|
||||
* Action triggered prior to the ActivityPub profile being created and sent to the client.
|
||||
*/
|
||||
\do_action( 'activitypub_rest_nodeinfo2_pre' );
|
||||
|
||||
$nodeinfo = array();
|
||||
|
||||
$nodeinfo['version'] = '2.0';
|
||||
$nodeinfo['server'] = array(
|
||||
'baseUrl' => \home_url( '/' ),
|
||||
'name' => \get_bloginfo( 'name' ),
|
||||
$nodeinfo['server'] = array(
|
||||
'baseUrl' => \home_url( '/' ),
|
||||
'name' => \get_bloginfo( 'name' ),
|
||||
'software' => 'wordpress',
|
||||
'version' => get_masked_wp_version(),
|
||||
'version' => get_masked_wp_version(),
|
||||
);
|
||||
|
||||
$posts = \wp_count_posts();
|
||||
$posts = \wp_count_posts();
|
||||
$comments = \wp_count_comments();
|
||||
|
||||
$nodeinfo['usage'] = array(
|
||||
'users' => array(
|
||||
'users' => array(
|
||||
'total' => get_total_users(),
|
||||
'activeMonth' => get_active_users( 1 ),
|
||||
'activeHalfyear' => get_active_users( 6 ),
|
||||
),
|
||||
'localPosts' => (int) $posts->publish,
|
||||
'localPosts' => (int) $posts->publish,
|
||||
'localComments' => (int) $comments->approved,
|
||||
);
|
||||
|
||||
$nodeinfo['openRegistrations'] = false;
|
||||
$nodeinfo['protocols'] = array( 'activitypub' );
|
||||
$nodeinfo['protocols'] = array( 'activitypub' );
|
||||
|
||||
$nodeinfo['services'] = array(
|
||||
'inbound' => array(),
|
||||
'inbound' => array(),
|
||||
'outbound' => array(),
|
||||
);
|
||||
|
||||
@ -163,21 +165,19 @@ class Nodeinfo {
|
||||
}
|
||||
|
||||
/**
|
||||
* Render NodeInfo discovery file
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* Render NodeInfo discovery file.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function discovery( $request ) {
|
||||
$discovery = array();
|
||||
public static function discovery() {
|
||||
$discovery = array();
|
||||
$discovery['links'] = array(
|
||||
array(
|
||||
'rel' => 'http://nodeinfo.diaspora.software/ns/schema/2.0',
|
||||
'rel' => 'http://nodeinfo.diaspora.software/ns/schema/2.0',
|
||||
'href' => get_rest_url_by_path( 'nodeinfo' ),
|
||||
),
|
||||
array(
|
||||
'rel' => 'https://www.w3.org/ns/activitystreams#Application',
|
||||
'rel' => 'https://www.w3.org/ns/activitystreams#Application',
|
||||
'href' => get_rest_url_by_path( 'application' ),
|
||||
),
|
||||
);
|
||||
|
@ -1,8 +1,13 @@
|
||||
<?php
|
||||
/**
|
||||
* Outbox REST-Class file.
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use stdClass;
|
||||
use WP_Error;
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Response;
|
||||
use Activitypub\Activity\Activity;
|
||||
@ -14,7 +19,7 @@ use function Activitypub\get_rest_url_by_path;
|
||||
use function Activitypub\get_masked_wp_version;
|
||||
|
||||
/**
|
||||
* ActivityPub Outbox REST-Class
|
||||
* ActivityPub Outbox REST-Class.
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*
|
||||
@ -22,7 +27,7 @@ use function Activitypub\get_masked_wp_version;
|
||||
*/
|
||||
class Outbox {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
@ -49,8 +54,8 @@ class Outbox {
|
||||
/**
|
||||
* Renders the user-outbox
|
||||
*
|
||||
* @param WP_REST_Request $request
|
||||
* @return WP_REST_Response
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
* @return WP_REST_Response|\WP_Error The response object or WP_Error.
|
||||
*/
|
||||
public static function user_outbox_get( $request ) {
|
||||
$user_id = $request->get_param( 'user_id' );
|
||||
@ -64,41 +69,43 @@ class Outbox {
|
||||
|
||||
$page = $request->get_param( 'page', 1 );
|
||||
|
||||
/*
|
||||
* Action triggerd prior to the ActivityPub profile being created and sent to the client
|
||||
/**
|
||||
* Action triggered prior to the ActivityPub profile being created and sent to the client.
|
||||
*/
|
||||
\do_action( 'activitypub_rest_outbox_pre' );
|
||||
|
||||
$json = new stdClass();
|
||||
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$json->{'@context'} = get_context();
|
||||
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/outbox', $user_id ) );
|
||||
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
|
||||
$json->actor = $user->get_id();
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/outbox', $user_id ) ); // phpcs:ignore
|
||||
$json->totalItems = 0; // phpcs:ignore
|
||||
$json->id = get_rest_url_by_path( sprintf( 'actors/%d/outbox', $user_id ) );
|
||||
$json->generator = 'http://wordpress.org/?v=' . get_masked_wp_version();
|
||||
$json->actor = $user->get_id();
|
||||
$json->type = 'OrderedCollectionPage';
|
||||
$json->partOf = get_rest_url_by_path( sprintf( 'actors/%d/outbox', $user_id ) );
|
||||
$json->totalItems = 0;
|
||||
|
||||
if ( $user_id > 0 ) {
|
||||
$count_posts = \count_user_posts( $user_id, $post_types, true );
|
||||
$json->totalItems = \intval( $count_posts ); // phpcs:ignore
|
||||
$count_posts = \count_user_posts( $user_id, $post_types, true );
|
||||
$json->totalItems = \intval( $count_posts );
|
||||
} else {
|
||||
foreach ( $post_types as $post_type ) {
|
||||
$count_posts = \wp_count_posts( $post_type );
|
||||
$json->totalItems += \intval( $count_posts->publish ); // phpcs:ignore
|
||||
$count_posts = \wp_count_posts( $post_type );
|
||||
$json->totalItems += \intval( $count_posts->publish );
|
||||
}
|
||||
}
|
||||
|
||||
$json->first = \add_query_arg( 'page', 1, $json->partOf ); // phpcs:ignore
|
||||
$json->last = \add_query_arg( 'page', \ceil ( $json->totalItems / 10 ), $json->partOf ); // phpcs:ignore
|
||||
$json->first = \add_query_arg( 'page', 1, $json->partOf );
|
||||
$json->last = \add_query_arg( 'page', \ceil( $json->totalItems / 10 ), $json->partOf );
|
||||
|
||||
if ( $page && ( ( \ceil ( $json->totalItems / 10 ) ) > $page ) ) { // phpcs:ignore
|
||||
$json->next = \add_query_arg( 'page', $page + 1, $json->partOf ); // phpcs:ignore
|
||||
if ( $page && ( ( \ceil( $json->totalItems / 10 ) ) > $page ) ) {
|
||||
$json->next = \add_query_arg( 'page', $page + 1, $json->partOf );
|
||||
}
|
||||
|
||||
if ( $page && ( $page > 1 ) ) { // phpcs:ignore
|
||||
$json->prev = \add_query_arg( 'page', $page - 1, $json->partOf ); // phpcs:ignore
|
||||
if ( $page && ( $page > 1 ) ) {
|
||||
$json->prev = \add_query_arg( 'page', $page - 1, $json->partOf );
|
||||
}
|
||||
// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
|
||||
if ( $page ) {
|
||||
$posts = \get_posts(
|
||||
@ -121,15 +128,19 @@ class Outbox {
|
||||
$activity = new Activity();
|
||||
$activity->set_type( 'Create' );
|
||||
$activity->set_object( $post );
|
||||
$json->orderedItems[] = $activity->to_array( false ); // phpcs:ignore
|
||||
$json->orderedItems[] = $activity->to_array( false ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
}
|
||||
}
|
||||
|
||||
// filter output
|
||||
/**
|
||||
* Filter the ActivityPub outbox array.
|
||||
*
|
||||
* @param array $json The ActivityPub outbox array.
|
||||
*/
|
||||
$json = \apply_filters( 'activitypub_rest_outbox_array', $json );
|
||||
|
||||
/*
|
||||
* Action triggerd after the ActivityPub profile has been created and sent to the client
|
||||
/**
|
||||
* Action triggered after the ActivityPub profile has been created and sent to the client
|
||||
*/
|
||||
\do_action( 'activitypub_outbox_post' );
|
||||
|
||||
@ -140,21 +151,21 @@ class Outbox {
|
||||
}
|
||||
|
||||
/**
|
||||
* The supported parameters
|
||||
* The supported parameters.
|
||||
*
|
||||
* @return array list of parameters
|
||||
* @return array List of parameters.
|
||||
*/
|
||||
public static function request_parameters() {
|
||||
$params = array();
|
||||
|
||||
$params['page'] = array(
|
||||
'type' => 'integer',
|
||||
'type' => 'integer',
|
||||
'default' => 1,
|
||||
);
|
||||
|
||||
$params['user_id'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'type' => 'string',
|
||||
);
|
||||
|
||||
return $params;
|
||||
|
@ -1,14 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* Server REST-Class file.
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use stdClass;
|
||||
use WP_Error;
|
||||
use WP_REST_Response;
|
||||
use Activitypub\Signature;
|
||||
use Activitypub\Model\Application;
|
||||
|
||||
/**
|
||||
* ActivityPub Server REST-Class
|
||||
* ActivityPub Server REST-Class.
|
||||
*
|
||||
* @author Django Doucet
|
||||
*
|
||||
@ -16,11 +21,12 @@ use Activitypub\Model\Application;
|
||||
*/
|
||||
class Server {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
|
||||
\add_filter( 'rest_request_before_callbacks', array( self::class, 'validate_activitypub_requests' ), 9, 3 );
|
||||
\add_filter( 'rest_request_before_callbacks', array( self::class, 'authorize_activitypub_requests' ), 10, 3 );
|
||||
}
|
||||
|
||||
@ -65,10 +71,10 @@ class Server {
|
||||
* @see https://www.w3.org/wiki/SocialCG/ActivityPub/Primer/Authentication_Authorization#Authorized_fetch
|
||||
* @see https://swicg.github.io/activitypub-http-signature/#authorized-fetch
|
||||
*
|
||||
* @param WP_REST_Response|WP_HTTP_Response|WP_Error|mixed $response Result to send to the client.
|
||||
* Usually a WP_REST_Response or WP_Error.
|
||||
* @param array $handler Route handler used for the request.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
* @param WP_REST_Response|\WP_HTTP_Response|WP_Error|mixed $response Result to send to the client.
|
||||
* Usually a WP_REST_Response or WP_Error.
|
||||
* @param array $handler Route handler used for the request.
|
||||
* @param \WP_REST_Request $request Request used to generate the response.
|
||||
*
|
||||
* @return mixed|WP_Error The response, error, or modified response.
|
||||
*/
|
||||
@ -77,9 +83,13 @@ class Server {
|
||||
return $response;
|
||||
}
|
||||
|
||||
if ( \is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$route = $request->get_route();
|
||||
|
||||
// check if it is an activitypub request and exclude webfinger and nodeinfo endpoints
|
||||
// Check if it is an activitypub request and exclude webfinger and nodeinfo endpoints.
|
||||
if (
|
||||
! \str_starts_with( $route, '/' . ACTIVITYPUB_REST_NAMESPACE ) ||
|
||||
\str_starts_with( $route, '/' . \trailingslashit( ACTIVITYPUB_REST_NAMESPACE ) . 'webfinger' ) ||
|
||||
@ -90,13 +100,13 @@ class Server {
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter to defer signature verification
|
||||
* Filter to defer signature verification.
|
||||
*
|
||||
* Skip signature verification for debugging purposes or to reduce load for
|
||||
* certain Activity-Types, like "Delete".
|
||||
*
|
||||
* @param bool $defer Whether to defer signature verification.
|
||||
* @param WP_REST_Request $request The request used to generate the response.
|
||||
* @param bool $defer Whether to defer signature verification.
|
||||
* @param \WP_REST_Request $request The request used to generate the response.
|
||||
*
|
||||
* @return bool Whether to defer signature verification.
|
||||
*/
|
||||
@ -107,9 +117,9 @@ class Server {
|
||||
}
|
||||
|
||||
if (
|
||||
// POST-Requests are always signed
|
||||
// POST-Requests are always signed.
|
||||
'GET' !== $request->get_method() ||
|
||||
// GET-Requests only require a signature in secure mode
|
||||
// GET-Requests only require a signature in secure mode.
|
||||
( 'GET' === $request->get_method() && ACTIVITYPUB_AUTHORIZED_FETCH )
|
||||
) {
|
||||
$verified_request = Signature::verify_http_signature( $request );
|
||||
@ -124,4 +134,51 @@ class Server {
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to validate incoming ActivityPub requests
|
||||
*
|
||||
* @param WP_REST_Response|\WP_HTTP_Response|WP_Error|mixed $response Result to send to the client.
|
||||
* Usually a WP_REST_Response or WP_Error.
|
||||
* @param array $handler Route handler used for the request.
|
||||
* @param \WP_REST_Request $request Request used to generate the response.
|
||||
*
|
||||
* @return mixed|WP_Error The response, error, or modified response.
|
||||
*/
|
||||
public static function validate_activitypub_requests( $response, $handler, $request ) {
|
||||
if ( 'HEAD' === $request->get_method() ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$route = $request->get_route();
|
||||
|
||||
if (
|
||||
\is_wp_error( $response ) ||
|
||||
! \str_starts_with( $route, '/' . ACTIVITYPUB_REST_NAMESPACE )
|
||||
) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$params = $request->get_json_params();
|
||||
|
||||
// Type is required for ActivityPub requests, so it fail later in the process.
|
||||
if ( ! isset( $params['type'] ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
if (
|
||||
ACTIVITYPUB_DISABLE_INCOMING_INTERACTIONS &&
|
||||
in_array( $params['type'], array( 'Create', 'Like', 'Announce' ), true )
|
||||
) {
|
||||
return new WP_Error(
|
||||
'activitypub_server_does_not_accept_incoming_interactions',
|
||||
\__( 'This server does not accept incoming interactions.', 'activitypub' ),
|
||||
// We have to use a 2XX status code here, because otherwise the response will be
|
||||
// treated as an error and Mastodon might block this WordPress instance.
|
||||
array( 'status' => 202 )
|
||||
);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* WebFinger REST-Class file.
|
||||
*
|
||||
* @package Activitypub
|
||||
*/
|
||||
|
||||
namespace Activitypub\Rest;
|
||||
|
||||
use WP_Error;
|
||||
use WP_REST_Response;
|
||||
use Activitypub\Collection\Users as User_Collection;
|
||||
|
||||
/**
|
||||
* ActivityPub WebFinger REST-Class
|
||||
* ActivityPub WebFinger REST-Class.
|
||||
*
|
||||
* @author Matthias Pfefferle
|
||||
*
|
||||
@ -15,8 +19,6 @@ use Activitypub\Collection\Users as User_Collection;
|
||||
class Webfinger {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function init() {
|
||||
self::register_routes();
|
||||
@ -24,8 +26,6 @@ class Webfinger {
|
||||
|
||||
/**
|
||||
* Register routes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
@ -45,13 +45,13 @@ class Webfinger {
|
||||
/**
|
||||
* WebFinger endpoint.
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response The response object.
|
||||
*/
|
||||
public static function webfinger( $request ) {
|
||||
/*
|
||||
* Action triggerd prior to the ActivityPub profile being created and sent to the client
|
||||
/**
|
||||
* Action triggered prior to the ActivityPub profile being created and sent to the client.
|
||||
*/
|
||||
\do_action( 'activitypub_rest_webfinger_pre' );
|
||||
|
||||
@ -74,13 +74,13 @@ class Webfinger {
|
||||
$code,
|
||||
array(
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Content-Type' => 'application/jrd+json; charset=' . get_option( 'blog_charset' ),
|
||||
'Content-Type' => 'application/jrd+json; charset=' . get_option( 'blog_charset' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The supported parameters
|
||||
* The supported parameters.
|
||||
*
|
||||
* @return array list of parameters
|
||||
*/
|
||||
@ -89,8 +89,8 @@ class Webfinger {
|
||||
|
||||
$params['resource'] = array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'pattern' => '^(acct:)|^(https?://)(.+)$',
|
||||
'type' => 'string',
|
||||
'pattern' => '^(acct:)|^(https?://)(.+)$',
|
||||
);
|
||||
|
||||
return $params;
|
||||
@ -99,47 +99,17 @@ class Webfinger {
|
||||
/**
|
||||
* Get the WebFinger profile.
|
||||
*
|
||||
* @param string $resource the WebFinger resource.
|
||||
* @param string $webfinger the WebFinger resource.
|
||||
*
|
||||
* @return array the WebFinger profile.
|
||||
* @return array|\WP_Error The WebFinger profile or WP_Error if not found.
|
||||
*/
|
||||
public static function get_profile( $resource ) {
|
||||
$user = User_Collection::get_by_resource( $resource );
|
||||
|
||||
if ( \is_wp_error( $user ) ) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
$aliases = array(
|
||||
$user->get_url(),
|
||||
$user->get_alternate_url(),
|
||||
);
|
||||
|
||||
$aliases = array_unique( $aliases );
|
||||
|
||||
$profile = array(
|
||||
'subject' => sprintf( 'acct:%s', $user->get_webfinger() ),
|
||||
'aliases' => array_values( array_unique( $aliases ) ),
|
||||
'links' => array(
|
||||
array(
|
||||
'rel' => 'self',
|
||||
'type' => 'application/activity+json',
|
||||
'href' => $user->get_url(),
|
||||
),
|
||||
array(
|
||||
'rel' => 'http://webfinger.net/rel/profile-page',
|
||||
'type' => 'text/html',
|
||||
'href' => $user->get_url(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if ( 'Person' !== $user->get_type() ) {
|
||||
$profile['links'][0]['properties'] = array(
|
||||
'https://www.w3.org/ns/activitystreams#type' => $user->get_type(),
|
||||
);
|
||||
}
|
||||
|
||||
return $profile;
|
||||
public static function get_profile( $webfinger ) {
|
||||
/**
|
||||
* Filter the WebFinger data.
|
||||
*
|
||||
* @param array $data The WebFinger data.
|
||||
* @param string $webfinger The WebFinger resource.
|
||||
*/
|
||||
return apply_filters( 'webfinger_data', array(), $webfinger );
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user