installed plugin Event Bridge for ActivityPub
version 1.1.0
This commit is contained in:
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* Accept handler file.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
* @since 1.0.0
|
||||
* @license AGPL-3.0-or-later */
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||
|
||||
use Activitypub\Collection\Actors;
|
||||
use Activitypub\Model\Blog;
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source;
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources as Event_Sources_Collection;
|
||||
|
||||
use function Activitypub\object_to_uri;
|
||||
|
||||
/**
|
||||
* Handle Accept requests.
|
||||
*/
|
||||
class Accept {
|
||||
/**
|
||||
* Initialize the class, registering the handler for incoming `Accept` activities to the ActivityPub plugin.
|
||||
*/
|
||||
public static function init(): void {
|
||||
\add_action(
|
||||
'activitypub_inbox_accept',
|
||||
array( self::class, 'handle_accept' ),
|
||||
15,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming "Accept" activities.
|
||||
*
|
||||
* @param array $activity The activity-object.
|
||||
* @param int $user_id The id of the local blog-user.
|
||||
*/
|
||||
public static function handle_accept( $activity, $user_id ): void {
|
||||
// We only process activities that are target to the blog actor.
|
||||
if ( Actors::BLOG_USER_ID !== $user_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we are actually following/or have a pending follow request this actor.
|
||||
$event_source_post_id = Event_Source::get_post_id_by_activitypub_id( $activity['actor'] );
|
||||
if ( ! $event_source_post_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This is what the ID of the follow request would look like.
|
||||
$application = new Blog();
|
||||
$follow_id = Event_Sources_Collection::compose_follow_id( $application->get_id(), $activity['actor'] );
|
||||
|
||||
// Check if the object of the `Accept` is indeed the `Follow` request we sent to that actor.
|
||||
if ( object_to_uri( $activity['object'] ) !== $follow_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the accept status of the follow request to the event source post.
|
||||
\update_post_meta( $event_source_post_id, '_event_bridge_for_activitypub_accept_of_follow', $activity['id'] );
|
||||
\wp_update_post(
|
||||
array(
|
||||
'ID' => $event_source_post_id,
|
||||
'post_status' => 'publish',
|
||||
)
|
||||
);
|
||||
|
||||
// Trigger the backfilling of events from this actor.
|
||||
\do_action( 'event_bridge_for_activitypub_backfill_events', $event_source_post_id );
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* Create handler file.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
*/
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||
|
||||
use Activitypub\Collection\Actors;
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source;
|
||||
use Event_Bridge_For_ActivityPub\Event_Sources;
|
||||
use Event_Bridge_For_ActivityPub\Setup;
|
||||
|
||||
use function Activitypub\is_activity_public;
|
||||
|
||||
/**
|
||||
* Handle Create requests.
|
||||
*/
|
||||
class Create {
|
||||
/**
|
||||
* Initialize the class, registering the handler for incoming `Create` activities to the ActivityPub plugin.
|
||||
*/
|
||||
public static function init(): void {
|
||||
\add_action(
|
||||
'activitypub_inbox_create',
|
||||
array( self::class, 'handle_create' ),
|
||||
15,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming "Create" activities.
|
||||
*
|
||||
* @param array $activity The activity-object.
|
||||
* @param int $user_id The id of the local blog-user.
|
||||
*/
|
||||
public static function handle_create( $activity, $user_id ): void {
|
||||
// We only process activities that are target to the blog actor.
|
||||
if ( Actors::BLOG_USER_ID !== $user_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if Activity is public or not.
|
||||
if ( ! is_activity_public( $activity ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if an object is set and it is an object of type `Event`.
|
||||
if ( ! isset( $activity['object']['type'] ) || 'Event' !== $activity['object']['type'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we are actually following/or have a pending follow request this actor.
|
||||
$event_source_post_id = Event_Source::get_post_id_by_activitypub_id( $activity['actor'] );
|
||||
if ( ! $event_source_post_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Event_Sources::is_time_passed( $activity['object']['startTime'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transmogrifier = Setup::get_transmogrifier();
|
||||
|
||||
if ( ! $transmogrifier ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transmogrifier::save( $activity['object'], $event_source_post_id );
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/**
|
||||
* Delete handler file.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
*/
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||
|
||||
use Activitypub\Collection\Actors;
|
||||
use Event_Bridge_For_ActivityPub\Event_Sources;
|
||||
use Event_Bridge_For_ActivityPub\Setup;
|
||||
|
||||
use function Activitypub\object_to_uri;
|
||||
|
||||
/**
|
||||
* Handle Delete requests.
|
||||
*/
|
||||
class Delete {
|
||||
/**
|
||||
* Initialize the class, registering the handler for incoming `Delete` activities to the ActivityPub plugin.
|
||||
*/
|
||||
public static function init() {
|
||||
\add_action(
|
||||
'activitypub_inbox_delete',
|
||||
array( self::class, 'handle_delete' ),
|
||||
15,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle "Follow" requests.
|
||||
*
|
||||
* @param array $activity The activity-object.
|
||||
* @param int $user_id The id of the local blog-user.
|
||||
*/
|
||||
public static function handle_delete( $activity, $user_id ): void {
|
||||
// We only process activities that are target to the application user.
|
||||
if ( Actors::BLOG_USER_ID !== $user_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we are actually following this actor.
|
||||
if ( ! Event_Sources::actor_is_event_source( $activity['actor'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$id = object_to_uri( $activity['object'] );
|
||||
|
||||
$transmogrifier = Setup::get_transmogrifier();
|
||||
|
||||
if ( ! $transmogrifier ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transmogrifier::delete( $id );
|
||||
}
|
||||
}
|
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
/**
|
||||
* Join handler file.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
* @license AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler;
|
||||
|
||||
use Activitypub\Activity\Activity;
|
||||
use Activitypub\Collection\Actors;
|
||||
use Activitypub\Activity\Actor;
|
||||
use Activitypub\Http;
|
||||
use Activitypub\Transformer\Factory;
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event as Event_Transformer;
|
||||
|
||||
use function Activitypub\get_remote_metadata_by_actor;
|
||||
use function Activitypub\object_to_uri;
|
||||
|
||||
/**
|
||||
* Handle Join requests.
|
||||
*/
|
||||
class Join {
|
||||
/**
|
||||
* Initialize the class, registering WordPress hooks.
|
||||
*/
|
||||
public static function init() {
|
||||
\add_action(
|
||||
'activitypub_register_handlers',
|
||||
array( self::class, 'register_join_handler' )
|
||||
);
|
||||
|
||||
\add_action(
|
||||
'event_bridge_for_activitypub_ignore_join',
|
||||
array( self::class, 'send_ignore_response' ),
|
||||
10,
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the join handler to the ActivityPub plugin.
|
||||
*/
|
||||
public static function register_join_handler() {
|
||||
\add_action(
|
||||
'activitypub_inbox_join',
|
||||
array( self::class, 'handle_join' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle ActivityPub "Join" requests.
|
||||
*
|
||||
* @param array $activity The activity object.
|
||||
*/
|
||||
public static function handle_join( $activity ) {
|
||||
$actor = get_remote_metadata_by_actor( object_to_uri( $activity['actor'] ) );
|
||||
|
||||
// If we cannot fetch the actor, we cannot continue.
|
||||
if ( \is_wp_error( $actor ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This should be already validated, but just to be sure.
|
||||
if ( ! array_key_exists( 'object', $activity ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the WordPress Post ID, via the ActivityPub ID.
|
||||
$post_id = self::get_post_id_by_activitypub_id( \sanitize_url( object_to_uri( $activity['object'] ) ) );
|
||||
|
||||
if ( ! $post_id ) {
|
||||
// No post is found for this URL/ID.
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether the target object/post is an event post.
|
||||
|
||||
$transformer = Factory::get_transformer( get_post( $post_id ) );
|
||||
|
||||
if ( ! $transformer instanceof Event_Transformer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass over to Event plugin specific handler if implemented here. Until then just send an ignore.
|
||||
do_action(
|
||||
'event_bridge_for_activitypub_ignore_join',
|
||||
$transformer->get_actor_object()->get_id(), // Gets the WordPress user that "owns" the object by ActivityPub means.
|
||||
$activity['id'],
|
||||
Actor::init_from_array( $actor )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send "Ignore" response.
|
||||
*
|
||||
* @param string $actor The actors ActivityPub ID which sends the response.
|
||||
* @param string $ignored The ID of the Activity that gets ignored.
|
||||
* @param Actor|mixed $to The target actor.
|
||||
*/
|
||||
public static function send_ignore_response( $actor, $ignored, $to ) {
|
||||
// Get actor object that owns the object that was targeted by the ignored activity.
|
||||
$actor = Actors::get_by_resource( $actor );
|
||||
|
||||
if ( \is_wp_error( $to ) || \is_wp_error( $actor ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get inbox.
|
||||
$inbox = $to->get_inbox();
|
||||
|
||||
if ( ! $inbox ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Send "Ignore" activity.
|
||||
$activity = new Activity();
|
||||
$activity->set_type( 'Ignore' );
|
||||
$activity->set_object( \esc_url_raw( $ignored ) );
|
||||
$activity->set_actor( $actor->get_id() );
|
||||
$activity->set_to( $to->get_id() );
|
||||
$activity->set_id( $actor->get_id() . '#ignore-' . \preg_replace( '~^https?://~', '', $ignored ) );
|
||||
$activity->set_sensitive( null );
|
||||
|
||||
// @phpstan-ignore-next-line
|
||||
Http::post( $inbox, $activity->to_json(), $actor->get__id() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WordPress Post ID by the ActivityPub ID.
|
||||
*
|
||||
* @param string $activitypub_id The ActivityPub objects ID.
|
||||
* @return int The WordPress post ID.
|
||||
*/
|
||||
private static function get_post_id_by_activitypub_id( $activitypub_id ) {
|
||||
// Parse the URL and extract its components.
|
||||
$parsed_url = wp_parse_url( $activitypub_id );
|
||||
$home_url = \trailingslashit( \home_url() );
|
||||
|
||||
// Ensure the base URL matches the home URL.
|
||||
if ( \trailingslashit( "{$parsed_url['scheme']}://{$parsed_url['host']}" ) !== $home_url ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check for a valid query string and parse it.
|
||||
if ( isset( $parsed_url['query'] ) ) {
|
||||
parse_str( $parsed_url['query'], $query_vars );
|
||||
|
||||
// Ensure the only parameter is 'p'.
|
||||
if ( count( $query_vars ) === 1 && isset( $query_vars['p'] ) ) {
|
||||
return intval( $query_vars['p'] ); // Return the post ID.
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: legacy ActivityPub plugin (before version 3.0.0) used pretty permalinks as `id`.
|
||||
return \url_to_postid( $activitypub_id );
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* Undo handler file.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
* @since 1.0.0
|
||||
* @license AGPL-3.0-or-later */
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||
|
||||
use Activitypub\Collection\Actors;
|
||||
use Event_Bridge_For_ActivityPub\Event_Sources;
|
||||
|
||||
use function Activitypub\object_to_uri;
|
||||
|
||||
/**
|
||||
* Handle Uno requests.
|
||||
*/
|
||||
class Undo {
|
||||
/**
|
||||
* Initialize the class, registering the handler for incoming `Uno` activities to the ActivityPub plugin.
|
||||
*/
|
||||
public static function init(): void {
|
||||
\add_action(
|
||||
'activitypub_inbox_undo',
|
||||
array( self::class, 'handle_undo' ),
|
||||
15,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming "Undo" activities.
|
||||
*
|
||||
* @param array $activity The activity-object.
|
||||
* @param int $user_id The id of the local blog-user.
|
||||
*/
|
||||
public static function handle_undo( $activity, $user_id ): void {
|
||||
// We only process activities that are target to the blog actor.
|
||||
if ( Actors::BLOG_USER_ID !== $user_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we are actually following/or have a pending follow request for this actor.
|
||||
if ( ! Event_Sources::actor_is_event_source( $activity['actor'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$accept_id = \sanitize_url( object_to_uri( $activity['object'] ) );
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$results = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s",
|
||||
'_event_bridge_for_activitypub_accept_of_follow',
|
||||
$accept_id
|
||||
)
|
||||
);
|
||||
|
||||
// If no event source with that accept ID is found return.
|
||||
if ( empty( $results ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post_id = reset( $results )->post_id;
|
||||
|
||||
\delete_post_meta( $post_id, '_event_bridge_for_activitypub_accept_of_follow' );
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* Update handler file.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
*/
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||
|
||||
use Activitypub\Collection\Actors;
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source;
|
||||
use Event_Bridge_For_ActivityPub\Event_Sources;
|
||||
use Event_Bridge_For_ActivityPub\Setup;
|
||||
|
||||
use function Activitypub\is_activity_public;
|
||||
|
||||
/**
|
||||
* Handle Update requests.
|
||||
*/
|
||||
class Update {
|
||||
/**
|
||||
* Initialize the class, registering the handler for incoming `Update` activities to the ActivityPub plugin.
|
||||
*/
|
||||
public static function init(): void {
|
||||
\add_action(
|
||||
'activitypub_inbox_update',
|
||||
array( self::class, 'handle_update' ),
|
||||
15,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming "Update" activities..
|
||||
*
|
||||
* @param array $activity The activity-object.
|
||||
* @param int $user_id The id of the local blog-user.
|
||||
*/
|
||||
public static function handle_update( $activity, $user_id ): void {
|
||||
// We only process activities that are target to the application user.
|
||||
if ( Actors::BLOG_USER_ID !== $user_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if Activity is public or not.
|
||||
if ( ! is_activity_public( $activity ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if an object is set and it is an object of type `Event`.
|
||||
if ( ! isset( $activity['object']['type'] ) || 'Event' !== $activity['object']['type'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we are actually following/or have a pending follow request this actor.
|
||||
$event_source_post_id = Event_Source::get_post_id_by_activitypub_id( $activity['actor'] );
|
||||
if ( ! $event_source_post_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Event_Sources::is_time_passed( $activity['object']['startTime'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transmogrifier = Setup::get_transmogrifier();
|
||||
|
||||
if ( ! $transmogrifier ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$transmogrifier::save( $activity['object'], $event_source_post_id );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user