Skip to content

Commit

Permalink
Merge branch 'master' into add/outbox-collection
Browse files Browse the repository at this point in the history
  • Loading branch information
pfefferle committed Dec 22, 2023
2 parents 6edc4b5 + a9c65f5 commit a38c565
Show file tree
Hide file tree
Showing 26 changed files with 1,165 additions and 235 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ Project maintained on GitHub at [automattic/wordpress-activitypub](https://githu
* Added: Make Post-Template filterable
* Added: CSS class for ActivityPub comments to allow custom designs
* Added: FEP-2677: Identifying the Application Actor
* Added: Basic Comment Federation
* Added: Profile Update Activities
* Improved: WebFinger endpoints

### 1.3.0 ###
Expand Down
5 changes: 3 additions & 2 deletions assets/js/activitypub-admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ jQuery( function( $ ) {
$( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false );
}
} );

$(document).on( 'wp-plugin-install-success', function( event, response ) {
setTimeout( function() {
$( '.activate-now' ).removeClass( 'thickbox open-plugin-details-modal' );
}, 1200 );
} );
} );

} );
47 changes: 32 additions & 15 deletions includes/activity/class-base-object.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,19 +254,6 @@ class Base_Object {
*/
protected $published;

/**
* A Collection containing objects considered to be responses to
* this object.
*
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-replies
*
* @var string
* | Collection
* | Link
* | null
*/
protected $replies;

/**
* The date and time describing the actual or expected starting time
* of the object.
Expand Down Expand Up @@ -437,6 +424,19 @@ class Base_Object {
*/
protected $source;

/**
* A Collection containing objects considered to be responses to
* this object.
*
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-replies
*
* @var string
* | Collection
* | Link
* | null
*/
protected $replies;

/**
* Magic function to implement getter and setter
*
Expand Down Expand Up @@ -671,8 +671,25 @@ public function to_array() {
* @return string The JSON string.
*/
public function to_json() {
$array = $this->to_array();
$array = $this->to_array();
$options = \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT;

/*
* Options to be passed to json_encode()
*
* @param int $options The current options flags
*/
$options = \apply_filters( 'activitypub_json_encode_options', $options );

return \wp_json_encode( $array, $options );
}

return \wp_json_encode( $array, \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT );
/**
* Returns the keys of the object vars.
*
* @return array The keys of the object vars.
*/
public function get_object_var_keys() {
return \array_keys( \get_object_vars( $this ) );
}
}
117 changes: 79 additions & 38 deletions includes/class-activity-dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
namespace Activitypub;

use WP_Post;
use WP_Comment;
use Activitypub\Activity\Activity;
use Activitypub\Collection\Users;
use Activitypub\Collection\Followers;
use Activitypub\Transformer\Factory;
use Activitypub\Transformer\Post;
use Activitypub\Transformer\Comment;

use function Activitypub\is_single_user;
use function Activitypub\is_user_disabled;
Expand All @@ -25,74 +28,67 @@ class Activity_Dispatcher {
public static function init() {
\add_action( 'activitypub_send_activity', array( self::class, 'send_activity' ), 10, 2 );
\add_action( 'activitypub_send_activity', array( self::class, 'send_activity_or_announce' ), 10, 2 );
\add_action( 'activitypub_send_update_profile_activity', array( self::class, 'send_profile_update' ), 10, 1 );
}

/**
* Send Activities to followers and mentioned users or `Announce` (boost) a blog post.
*
* @param WP_Post $wp_post The ActivityPub Post.
* @param string $type The Activity-Type.
* @param mixed $wp_object The ActivityPub Post.
* @param string $type The Activity-Type.
*
* @return void
*/
public static function send_activity_or_announce( WP_Post $wp_post, $type ) {
public static function send_activity_or_announce( $wp_object, $type ) {
// check if a migration is needed before sending new posts
Migration::maybe_migrate();

if ( is_user_type_disabled( 'blog' ) ) {
return;
}

$wp_post->post_author = Users::BLOG_USER_ID;

if ( is_single_user() ) {
self::send_activity( $wp_post, $type );
self::send_activity( $wp_object, $type, Users::BLOG_USER_ID );
} else {
self::send_announce( $wp_post, $type );
self::send_announce( $wp_object, $type );
}
}

/**
* Send Activities to followers and mentioned users.
*
* @param WP_Post $wp_post The ActivityPub Post.
* @param string $type The Activity-Type.
* @param mixed $wp_object The ActivityPub Post.
* @param string $type The Activity-Type.
*
* @return void
*/
public static function send_activity( WP_Post $wp_post, $type ) {
if ( is_user_disabled( $wp_post->post_author ) ) {
return;
}
public static function send_activity( $wp_object, $type, $user_id = null ) {
$transformer = Factory::get_transformer( $wp_object );

$object = Post::transform( $wp_post )->to_object();

$activity = new Activity();
$activity->set_type( $type );
$activity->set_object( $object );
if ( null !== $user_id ) {
$transformer->change_wp_user_id( $user_id );
}

$follower_inboxes = Followers::get_inboxes( $wp_post->post_author );
$mentioned_inboxes = Mention::get_inboxes( $activity->get_cc() );
$user_id = $transformer->get_wp_user_id();

$inboxes = array_merge( $follower_inboxes, $mentioned_inboxes );
$inboxes = array_unique( $inboxes );
if ( is_user_disabled( $user_id ) ) {
return;
}

$json = $activity->to_json();
$activity = $transformer->to_activity( $type );

foreach ( $inboxes as $inbox ) {
safe_remote_post( $inbox, $json, $wp_post->post_author );
}
self::send_activity_to_inboxes( $activity, $user_id );
}

/**
* Send Announces to followers and mentioned users.
*
* @param WP_Post $wp_post The ActivityPub Post.
* @param string $type The Activity-Type.
* @param mixed $wp_object The ActivityPub Post.
* @param string $type The Activity-Type.
*
* @return void
*/
public static function send_announce( WP_Post $wp_post, $type ) {
public static function send_announce( $wp_object, $type ) {
if ( ! in_array( $type, array( 'Create', 'Update' ), true ) ) {
return;
}
Expand All @@ -101,25 +97,70 @@ public static function send_announce( WP_Post $wp_post, $type ) {
return;
}

$object = Post::transform( $wp_post )->to_object();
$transformer = Factory::get_transformer( $wp_object );
$transformer->change_wp_user_id( Users::BLOG_USER_ID );

$user_id = $transformer->get_wp_user_id();
$activity = $transformer->to_activity( 'Announce' );

self::send_activity_to_inboxes( $activity, $user_id );
}

/**
* Send a "Update" Activity when a user updates their profile.
*
* @param int $user_id The user ID to send an update for.
*
* @return void
*/
public static function send_profile_update( $user_id ) {
$user = Users::get_by_various( $user_id );

// bail if that's not a good user
if ( is_wp_error( $user ) ) {
return;
}

// build the update
$activity = new Activity();
$activity->set_type( 'Announce' );
// to pre-fill attributes like "published" and "id"
$activity->set_object( $object );
// send only the id
$activity->set_object( $object->get_id() );
$activity->set_id( $user->get_url() . '#update' );
$activity->set_type( 'Update' );
$activity->set_actor( $user->get_url() );
$activity->set_object( $user->get_url() );
$activity->set_to( 'https://www.w3.org/ns/activitystreams#Public' );

// send the update
self::send_activity_to_inboxes( $activity, $user_id );
}

/**
* Send an Activity to all followers and mentioned users.
*
* @param Activity $activity The ActivityPub Activity.
* @param int $user_id The user ID.
*
* @return void
*/
private static function send_activity_to_inboxes( $activity, $user_id ) {
$follower_inboxes = Followers::get_inboxes( $user_id );

$follower_inboxes = Followers::get_inboxes( $wp_post->post_author );
$mentioned_inboxes = Mention::get_inboxes( $activity->get_cc() );
$mentioned_inboxes = array();
$cc = $activity->get_cc();
if ( $cc ) {
$mentioned_inboxes = Mention::get_inboxes( $cc );
}

$inboxes = array_merge( $follower_inboxes, $mentioned_inboxes );
$inboxes = array_unique( $inboxes );

if ( empty( $inboxes ) ) {
return;
}

$json = $activity->to_json();

foreach ( $inboxes as $inbox ) {
safe_remote_post( $inbox, $json, $wp_post->post_author );
safe_remote_post( $inbox, $json, $user_id );
}
}
}
52 changes: 49 additions & 3 deletions includes/class-activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

use function Activitypub\sanitize_url;

use function Activitypub\is_comment;
use function Activitypub\is_activitypub_request;

/**
* ActivityPub Class
*
Expand All @@ -20,6 +23,7 @@ class Activitypub {
*/
public static function init() {
\add_filter( 'template_include', array( self::class, 'render_json_template' ), 99 );
\add_action( 'template_redirect', array( self::class, 'template_redirect' ) );
\add_filter( 'query_vars', array( self::class, 'add_query_vars' ) );
\add_filter( 'pre_get_avatar_data', array( self::class, 'pre_get_avatar_data' ), 11, 2 );
\add_filter( 'get_comment_link', array( self::class, 'remote_comment_link' ), 11, 3 );
Expand Down Expand Up @@ -101,6 +105,8 @@ public static function render_json_template( $template ) {

if ( \is_author() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/author-json.php';
} elseif ( is_comment() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/comment-json.php';
} elseif ( \is_singular() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/post-json.php';
} elseif ( \is_home() ) {
Expand All @@ -118,11 +124,43 @@ public static function render_json_template( $template ) {
return $json_template;
}

/**
* Custom redirects for ActivityPub requests.
*
* @return void
*/
public static function template_redirect() {
$comment_id = get_query_var( 'c', null );

// check if it seems to be a comment
if ( ! $comment_id ) {
return;
}

$comment = get_comment( $comment_id );

// load a 404 page if `c` is set but not valid
if ( ! $comment ) {
global $wp_query;
$wp_query->set_404();
return;
}

// stop if it's not an ActivityPub comment
if ( is_activitypub_request() && $comment->user_id ) {
return;
}

wp_safe_redirect( get_comment_link( $comment ) );
}

/**
* Add the 'activitypub' query variable so WordPress won't mangle it.
*/
public static function add_query_vars( $vars ) {
$vars[] = 'activitypub';
$vars[] = 'c';
$vars[] = 'p';

return $vars;
}
Expand Down Expand Up @@ -198,10 +236,18 @@ public static function get_avatar_url( $comment ) {
* @return string $url
*/
public static function remote_comment_link( $comment_link, $comment ) {
$remote_comment_link = get_comment_meta( $comment->comment_ID, 'source_url', true );
if ( $remote_comment_link ) {
$comment_link = esc_url( $remote_comment_link );
if ( ! $comment || is_admin() ) {
return $comment_link;
}

$comment_meta = \get_comment_meta( $comment->comment_ID );

if ( ! empty( $comment_meta['source_url'][0] ) ) {
return $comment_meta['source_url'][0];
} elseif ( ! empty( $comment_meta['source_id'][0] ) ) {
return $comment_meta['source_id'][0];
}

return $comment_link;
}

Expand Down
Loading

0 comments on commit a38c565

Please sign in to comment.