WIP: Add Event Sources Logic (ActivityPub follows) #86
6 changed files with 178 additions and 83 deletions
|
@ -92,6 +92,16 @@ class Event_Sources {
|
|||
)
|
||||
);
|
||||
|
||||
\register_post_meta(
|
||||
self::POST_TYPE,
|
||||
'activitypub_inbox',
|
||||
array(
|
||||
'type' => 'string',
|
||||
'single' => true,
|
||||
'sanitize_callback' => 'sanitize_url',
|
||||
)
|
||||
);
|
||||
|
||||
\register_post_meta(
|
||||
self::POST_TYPE,
|
||||
'event_source_utilize_announces',
|
||||
|
@ -229,4 +239,140 @@ class Event_Sources {
|
|||
$post_id = Event_Source::get_wp_post_from_activitypub_actor_id( $event_source );
|
||||
return wp_delete_post( $post_id, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a hook to run async.
|
||||
*
|
||||
* @param string $hook The hook name.
|
||||
* @param array $args The arguments to pass to the hook.
|
||||
* @param string $unqueue_hook Optional a hook to unschedule before queuing.
|
||||
* @return void|bool Whether the hook was queued.
|
||||
*/
|
||||
public static function queue( $hook, $args, $unqueue_hook = null ) {
|
||||
if ( $unqueue_hook ) {
|
||||
$hook_timestamp = wp_next_scheduled( $unqueue_hook, $args );
|
||||
if ( $hook_timestamp ) {
|
||||
wp_unschedule_event( $hook_timestamp, $unqueue_hook, $args );
|
||||
}
|
||||
}
|
||||
|
||||
if ( wp_next_scheduled( $hook, $args ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
return \wp_schedule_single_event( \time(), $hook, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to follow an ActivityPub actor via a scheduled event.
|
||||
*
|
||||
* @param string $actor The ActivityPub actor.
|
||||
*
|
||||
* @return bool|WP_Error Whether the event was queued.
|
||||
*/
|
||||
public static function queue_follow_actor( $actor ) {
|
||||
$queued = self::queue(
|
||||
'event_bridge_for_activitypub_follow',
|
||||
$actor,
|
||||
'event_bridge_for_activitypub_unfollow'
|
||||
);
|
||||
|
||||
return $queued;
|
||||
}
|
||||
|
||||
/**
|
||||
* Follow an ActivityPub actor via the Application user.
|
||||
*
|
||||
* @param string $actor_id The ID/URL of the Actor.
|
||||
*/
|
||||
public static function activitypub_follow_actor( $actor_id ) {
|
||||
$post_id = Event_Source::get_wp_post_from_activitypub_actor_id( $actor_id );
|
||||
|
||||
if ( ! $post_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$actor = Event_Source::init_from_cpt( get_post( $post_id ) );
|
||||
|
||||
if ( is_wp_error( $actor ) ) {
|
||||
return $actor;
|
||||
}
|
||||
|
||||
$inbox = $actor->get_shared_inbox();
|
||||
$to = $actor->get_id();
|
||||
|
||||
$application = new \Activitypub\Model\Application();
|
||||
|
||||
$activity = new \Activitypub\Activity\Activity();
|
||||
$activity->set_type( 'Follow' );
|
||||
$activity->set_to( null );
|
||||
$activity->set_cc( null );
|
||||
$activity->set_actor( $application->get_id() );
|
||||
$activity->set_object( $to );
|
||||
$activity->set_id( $actor . '#follow-' . \preg_replace( '~^https?://~', '', $to ) );
|
||||
$activity = $activity->to_json();
|
||||
\Activitypub\safe_remote_post( $inbox, $activity, \Activitypub\Collection\Actors::APPLICATION_USER_ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to unfollow an actor via a scheduled event.
|
||||
*
|
||||
* @param string $actor The ActivityPub actor ID.
|
||||
*
|
||||
* @return bool|WP_Error Whether the event was queued.
|
||||
*/
|
||||
public static function queue_unfollow_actor( $actor ) {
|
||||
$queued = self::queue(
|
||||
'event_bridge_for_activitypub_unfollow',
|
||||
$actor,
|
||||
'event_bridge_for_activitypub_follow'
|
||||
);
|
||||
|
||||
return $queued;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unfollow an ActivityPub actor.
|
||||
*
|
||||
* @param string $actor_id The ActivityPub actor ID.
|
||||
*/
|
||||
public static function activitypub_unfollow_actor( $actor_id ) {
|
||||
$post_id = Event_Source::get_wp_post_from_activitypub_actor_id( $actor_id );
|
||||
|
||||
if ( ! $post_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$actor = Event_Source::init_from_cpt( get_post( $post_id ) );
|
||||
|
||||
if ( is_wp_error( $actor ) ) {
|
||||
return $actor;
|
||||
}
|
||||
|
||||
$inbox = $actor->get_shared_inbox();
|
||||
$to = $actor->get_id();
|
||||
|
||||
$application = new \Activitypub\Model\Application();
|
||||
|
||||
if ( is_wp_error( $inbox ) ) {
|
||||
return $inbox;
|
||||
}
|
||||
|
||||
$activity = new \Activitypub\Activity\Activity();
|
||||
$activity->set_type( 'Undo' );
|
||||
$activity->set_to( null );
|
||||
$activity->set_cc( null );
|
||||
$activity->set_actor( $application->get_id() );
|
||||
$activity->set_object(
|
||||
array(
|
||||
'type' => 'Follow',
|
||||
'actor' => $actor,
|
||||
'object' => $to,
|
||||
'id' => $to,
|
||||
)
|
||||
);
|
||||
$activity->set_id( $actor . '#unfollow-' . \preg_replace( '~^https?://~', '', $to ) );
|
||||
$activity = $activity->to_json();
|
||||
\Activitypub\safe_remote_post( $inbox, $activity, \Activitypub\Collection\Actors::APPLICATION_USER_ID );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
namespace Event_Bridge_For_ActivityPub\ActivityPub\Model;
|
||||
|
||||
use Activitypub\Activity\Actor;
|
||||
use Activitypub\Webfinger;
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources;
|
||||
use WP_Error;
|
||||
|
||||
|
@ -118,6 +117,32 @@ class Event_Source extends Actor {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the post meta.
|
||||
*/
|
||||
protected function get_post_meta_input() {
|
||||
$meta_input = array();
|
||||
$meta_input['activitypub_inbox'] = $this->get_shared_inbox();
|
||||
$meta_input['activitypub_actor_json'] = $this->to_json();
|
||||
|
||||
return $meta_input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shared inbox, with a fallback to the inbox.
|
||||
*
|
||||
* @return string|null The URL to the shared inbox, the inbox or null.
|
||||
*/
|
||||
public function get_shared_inbox() {
|
||||
if ( ! empty( $this->get_endpoints()['sharedInbox'] ) ) {
|
||||
return $this->get_endpoints()['sharedInbox'];
|
||||
} elseif ( ! empty( $this->get_inbox() ) ) {
|
||||
return $this->get_inbox();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the current Event Source object to Database within custom post type.
|
||||
*
|
||||
|
|
|
@ -9,11 +9,8 @@ namespace Event_Bridge_For_ActivityPub;
|
|||
|
||||
use Activitypub\Activity\Extended_Object\Event;
|
||||
use Activitypub\Collection\Actors;
|
||||
use Activitypub\Http;
|
||||
use Exception;
|
||||
|
||||
use function Activitypub\get_remote_metadata_by_actor;
|
||||
use function register_post_type;
|
||||
|
||||
/**
|
||||
* Class for handling and saving the ActivityPub event sources (i.e. follows).
|
||||
|
@ -30,83 +27,9 @@ class Event_Sources {
|
|||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
\add_action( 'init', array( $this, 'register_post_meta' ) );
|
||||
|
||||
\add_action( 'activitypub_inbox', array( $this, 'handle_activitypub_inbox' ), 15, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the post type used to store the external event sources (i.e., followed ActivityPub actors).
|
||||
*/
|
||||
public static function register_post_type() {
|
||||
register_post_type(
|
||||
self::POST_TYPE,
|
||||
array(
|
||||
'labels' => array(
|
||||
'name' => _x( 'Event Sources', 'post_type plural name', 'activitypub' ),
|
||||
'singular_name' => _x( 'Event Source', 'post_type single name', 'activitypub' ),
|
||||
),
|
||||
'public' => false,
|
||||
'hierarchical' => false,
|
||||
'rewrite' => false,
|
||||
'query_var' => false,
|
||||
'delete_with_user' => false,
|
||||
'can_export' => true,
|
||||
'supports' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
\register_post_meta(
|
||||
self::POST_TYPE,
|
||||
'activitypub_inbox',
|
||||
array(
|
||||
'type' => 'string',
|
||||
'single' => true,
|
||||
'sanitize_callback' => 'sanitize_url',
|
||||
)
|
||||
);
|
||||
|
||||
\register_post_meta(
|
||||
self::POST_TYPE,
|
||||
'activitypub_errors',
|
||||
array(
|
||||
'type' => 'string',
|
||||
'single' => false,
|
||||
'sanitize_callback' => function ( $value ) {
|
||||
if ( ! is_string( $value ) ) {
|
||||
throw new Exception( 'Error message is no valid string' );
|
||||
}
|
||||
|
||||
return esc_sql( $value );
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
\register_post_meta(
|
||||
self::POST_TYPE,
|
||||
'activitypub_user_id',
|
||||
array(
|
||||
'type' => 'string',
|
||||
'single' => false,
|
||||
'sanitize_callback' => function ( $value ) {
|
||||
return esc_sql( $value );
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
\register_post_meta(
|
||||
self::POST_TYPE,
|
||||
'activitypub_actor_json',
|
||||
array(
|
||||
'type' => 'string',
|
||||
'single' => true,
|
||||
'sanitize_callback' => function ( $value ) {
|
||||
return sanitize_text_field( $value );
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the ActivityPub Inbox.
|
||||
*
|
||||
|
|
|
@ -20,6 +20,7 @@ use Event_Bridge_For_ActivityPub\Admin\General_Admin_Notices;
|
|||
use Event_Bridge_For_ActivityPub\Admin\Health_Check;
|
||||
use Event_Bridge_For_ActivityPub\Admin\Settings_Page;
|
||||
use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin;
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources as Event_Sources_Collection;
|
||||
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
|
||||
|
@ -183,7 +184,7 @@ class Setup {
|
|||
}
|
||||
|
||||
add_action( 'init', array( Health_Check::class, 'init' ) );
|
||||
add_action( 'init', array( Event_Sources::class, 'register_post_type' ) );
|
||||
add_action( 'init', array( Event_Sources_Collection::class, 'register_post_type' ) );
|
||||
|
||||
// Check if the minimum required version of the ActivityPub plugin is installed.
|
||||
if ( ! version_compare( $this->activitypub_plugin_version, EVENT_BRIDGE_FOR_ACTIVITYPUB_ACTIVITYPUB_PLUGIN_MIN_VERSION ) ) {
|
||||
|
|
|
@ -95,7 +95,7 @@ class Event_Sources extends WP_List_Table {
|
|||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
$event_sources = Event_Sources_Collection::get_event_sources_with_count($per_page, $page_num, $args );
|
||||
$event_sources = Event_Sources_Collection::get_event_sources_with_count( $per_page, $page_num, $args );
|
||||
$actors = $event_sources['actors'];
|
||||
$counter = $event_sources['total'];
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ $table = new \Event_Bridge_For_ActivityPub\Table\Event_Sources();
|
|||
|
||||
<!-- Button that triggers ThickBox -->
|
||||
<a href="#TB_inline?width=600&height=400&inlineId=Event_Bridge_For_ActivityPub_add_new_source" class="thickbox button button-primary">
|
||||
<?php esc_html_e( 'Add new', 'event-bridge-for-activitypub' ); ?>
|
||||
<?php esc_html_e( 'Add Event Source', 'event-bridge-for-activitypub' ); ?>
|
||||
</a>
|
||||
|
||||
<!-- ThickBox content (hidden initially) -->
|
||||
|
@ -37,8 +37,8 @@ $table = new \Event_Bridge_For_ActivityPub\Table\Event_Sources();
|
|||
<p> <?php esc_html_e( 'Here you can enter either a Fediverse handle (@username@example.social), URL of an ActivityPub Account (https://example.social/user/username) or instance URL.', 'event-bridge-for-activitypub' ); ?> </p>
|
||||
<form method="post" action="options.php">
|
||||
<?php \settings_fields( 'event-bridge-for-activitypub-event-sources' ); ?>
|
||||
<input type="text" name="event_bridge_for_activitypub_event_source" id="event_bridge_for_activitypub_event_source" value="test">
|
||||
<?php \submit_button(); ?>
|
||||
<input type="text" name="event_bridge_for_activitypub_event_source" id="event_bridge_for_activitypub_event_source" value="">
|
||||
<?php \submit_button( __( 'Add Event Source', 'event-bridge-for-activitypub' ) ); ?>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue