added follower model
This commit is contained in:
parent
ef536cc977
commit
84a82c2ac4
9 changed files with 320 additions and 215 deletions
|
@ -29,6 +29,8 @@ function init() {
|
||||||
\define( 'ACTIVITYPUB_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
|
\define( 'ACTIVITYPUB_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
|
||||||
\define( 'ACTIVITYPUB_PLUGIN_FILE', plugin_dir_path( __FILE__ ) . '/' . basename( __FILE__ ) );
|
\define( 'ACTIVITYPUB_PLUGIN_FILE', plugin_dir_path( __FILE__ ) . '/' . basename( __FILE__ ) );
|
||||||
|
|
||||||
|
\define( 'ACTIVITYPUB_OBJECT', 'ACTIVITYPUB_OBJECT' );
|
||||||
|
|
||||||
require_once \dirname( __FILE__ ) . '/includes/table/class-followers.php';
|
require_once \dirname( __FILE__ ) . '/includes/table/class-followers.php';
|
||||||
require_once \dirname( __FILE__ ) . '/includes/class-signature.php';
|
require_once \dirname( __FILE__ ) . '/includes/class-signature.php';
|
||||||
require_once \dirname( __FILE__ ) . '/includes/class-webfinger.php';
|
require_once \dirname( __FILE__ ) . '/includes/class-webfinger.php';
|
||||||
|
@ -37,6 +39,7 @@ function init() {
|
||||||
|
|
||||||
require_once \dirname( __FILE__ ) . '/includes/model/class-activity.php';
|
require_once \dirname( __FILE__ ) . '/includes/model/class-activity.php';
|
||||||
require_once \dirname( __FILE__ ) . '/includes/model/class-post.php';
|
require_once \dirname( __FILE__ ) . '/includes/model/class-post.php';
|
||||||
|
require_once \dirname( __FILE__ ) . '/includes/model/class-follower.php';
|
||||||
|
|
||||||
require_once \dirname( __FILE__ ) . '/includes/class-activity-dispatcher.php';
|
require_once \dirname( __FILE__ ) . '/includes/class-activity-dispatcher.php';
|
||||||
Activity_Dispatcher::init();
|
Activity_Dispatcher::init();
|
||||||
|
|
|
@ -3,6 +3,7 @@ namespace Activitypub;
|
||||||
|
|
||||||
use Activitypub\Model\Post;
|
use Activitypub\Model\Post;
|
||||||
use Activitypub\Model\Activity;
|
use Activitypub\Model\Activity;
|
||||||
|
use Activitypub\Collection\Followers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ActivityPub Activity_Dispatcher Class
|
* ActivityPub Activity_Dispatcher Class
|
||||||
|
@ -66,11 +67,9 @@ class Activity_Dispatcher {
|
||||||
$activitypub_activity = new Activity( $activity_type );
|
$activitypub_activity = new Activity( $activity_type );
|
||||||
$activitypub_activity->from_post( $activitypub_post );
|
$activitypub_activity->from_post( $activitypub_post );
|
||||||
|
|
||||||
$inboxes = \Activitypub\get_follower_inboxes( $user_id, $activitypub_activity->get_cc() );
|
$inboxes = FollowerCollection::get_inboxes( $user_id );
|
||||||
|
|
||||||
foreach ( $inboxes as $inbox => $cc ) {
|
foreach ( $inboxes as $inbox ) {
|
||||||
$cc = array_values( array_unique( $cc ) );
|
|
||||||
$activitypub_activity->add_cc( $cc );
|
|
||||||
$activity = $activitypub_activity->to_json();
|
$activity = $activitypub_activity->to_json();
|
||||||
|
|
||||||
\Activitypub\safe_remote_post( $inbox, $activity, $user_id );
|
\Activitypub\safe_remote_post( $inbox, $activity, $user_id );
|
||||||
|
|
|
@ -5,10 +5,10 @@ use WP_Error;
|
||||||
use WP_Term_Query;
|
use WP_Term_Query;
|
||||||
use Activitypub\Webfinger;
|
use Activitypub\Webfinger;
|
||||||
use Activitypub\Model\Activity;
|
use Activitypub\Model\Activity;
|
||||||
|
use Activitypub\Model\Follower;
|
||||||
|
|
||||||
use function Activitypub\safe_remote_get;
|
use function Activitypub\safe_remote_get;
|
||||||
use function Activitypub\safe_remote_post;
|
use function Activitypub\safe_remote_post;
|
||||||
use function Activitypub\get_remote_metadata_by_actor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ActivityPub Followers Collection
|
* ActivityPub Followers Collection
|
||||||
|
@ -29,6 +29,8 @@ class Followers {
|
||||||
|
|
||||||
\add_action( 'activitypub_inbox_follow', array( self::class, 'handle_follow_request' ), 10, 2 );
|
\add_action( 'activitypub_inbox_follow', array( self::class, 'handle_follow_request' ), 10, 2 );
|
||||||
\add_action( 'activitypub_inbox_undo', array( self::class, 'handle_undo_request' ), 10, 2 );
|
\add_action( 'activitypub_inbox_undo', array( self::class, 'handle_undo_request' ), 10, 2 );
|
||||||
|
|
||||||
|
\add_action( 'activitypub_followers_post_follow', array( self::class, 'send_follow_response' ), 10, 4 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,16 +61,6 @@ class Followers {
|
||||||
register_taxonomy( self::TAXONOMY, 'user', $args );
|
register_taxonomy( self::TAXONOMY, 'user', $args );
|
||||||
register_taxonomy_for_object_type( self::TAXONOMY, 'user' );
|
register_taxonomy_for_object_type( self::TAXONOMY, 'user' );
|
||||||
|
|
||||||
register_term_meta(
|
|
||||||
self::TAXONOMY,
|
|
||||||
'user_id',
|
|
||||||
array(
|
|
||||||
'type' => 'string',
|
|
||||||
'single' => true,
|
|
||||||
//'sanitize_callback' => array( self::class, 'validate_username' ),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
register_term_meta(
|
register_term_meta(
|
||||||
self::TAXONOMY,
|
self::TAXONOMY,
|
||||||
'name',
|
'name',
|
||||||
|
@ -101,21 +93,21 @@ class Followers {
|
||||||
|
|
||||||
register_term_meta(
|
register_term_meta(
|
||||||
self::TAXONOMY,
|
self::TAXONOMY,
|
||||||
'created_at',
|
'inbox',
|
||||||
array(
|
array(
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'single' => true,
|
'single' => true,
|
||||||
//'sanitize_callback' => array( self::class, 'validate_created_at' ),
|
//'sanitize_callback' => array( self::class, 'validate_inbox' ),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
register_term_meta(
|
register_term_meta(
|
||||||
self::TAXONOMY,
|
self::TAXONOMY,
|
||||||
'inbox',
|
'updated_at',
|
||||||
array(
|
array(
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'single' => true,
|
'single' => true,
|
||||||
//'sanitize_callback' => array( self::class, 'validate_created_at' ),
|
//'sanitize_callback' => array( self::class, 'validate_updated_at' ),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -127,12 +119,13 @@ class Followers {
|
||||||
*
|
*
|
||||||
* @param array $object The JSON "Follow" Activity
|
* @param array $object The JSON "Follow" Activity
|
||||||
* @param int $user_id The ID of the WordPress User
|
* @param int $user_id The ID of the WordPress User
|
||||||
*
|
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function handle_follow_request( $object, $user_id ) {
|
public static function handle_follow_request( $object, $user_id ) {
|
||||||
// save follower
|
// save follower
|
||||||
self::add_follower( $user_id, $object['actor'] );
|
$follower = self::add_follower( $user_id, $object['actor'] );
|
||||||
|
|
||||||
|
do_action( 'activitypub_followers_post_follow', $object['actor'], $object, $user_id, $follower );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -156,68 +149,67 @@ class Followers {
|
||||||
*
|
*
|
||||||
* @param int $user_id The WordPress user
|
* @param int $user_id The WordPress user
|
||||||
* @param string $actor The Actor URL
|
* @param string $actor The Actor URL
|
||||||
* @return void
|
* @return array|WP_Error The Follower (WP_Term array) or an WP_Error
|
||||||
*/
|
*/
|
||||||
public static function add_follower( $user_id, $actor ) {
|
public static function add_follower( $user_id, $actor ) {
|
||||||
$remote_data = get_remote_metadata_by_actor( $actor );
|
$follower = new Follower( $actor );
|
||||||
|
$follower->upsert();
|
||||||
|
|
||||||
if ( ! $remote_data || is_wp_error( $remote_data ) || ! is_array( $remote_data ) ) {
|
$result = wp_set_object_terms( $user_id, $follower->get_actor(), self::TAXONOMY, true );
|
||||||
$remote_data = array();
|
|
||||||
|
if ( is_wp_error( $result ) ) {
|
||||||
|
return $result;
|
||||||
|
} else {
|
||||||
|
return $follower;
|
||||||
}
|
}
|
||||||
|
|
||||||
$term = term_exists( $actor, self::TAXONOMY );
|
|
||||||
|
|
||||||
if ( ! $term ) {
|
|
||||||
$term = wp_insert_term(
|
|
||||||
$actor,
|
|
||||||
self::TAXONOMY,
|
|
||||||
array(
|
|
||||||
'slug' => sanitize_title( $actor ),
|
|
||||||
'description' => wp_json_encode( $remote_data ),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$term_id = $term['term_id'];
|
|
||||||
|
|
||||||
$map_meta = array(
|
|
||||||
'name' => 'name',
|
|
||||||
'preferredUsername' => 'username',
|
|
||||||
'inbox' => 'inbox',
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach ( $map_meta as $remote => $internal ) {
|
|
||||||
if ( ! empty( $remote_data[ $remote ] ) ) {
|
|
||||||
update_term_meta( $term_id, $internal, esc_html( $remote_data[ $remote ] ), true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! empty( $remote_data['icon']['url'] ) ) {
|
|
||||||
update_term_meta( $term_id, 'avatar', esc_url_raw( $remote_data['icon']['url'] ), true );
|
|
||||||
}
|
|
||||||
|
|
||||||
wp_set_object_terms( $user_id, $actor, self::TAXONOMY, true );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function remove_follower( $user_id, $actor ) {
|
|
||||||
wp_remove_object_terms( $user_id, $actor, self::TAXONOMY );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undocumented function
|
* Remove a Follower
|
||||||
*
|
*
|
||||||
|
* @param int $user_id The WordPress user_id
|
||||||
|
* @param string $actor The Actor URL
|
||||||
|
* @return bool|WP_Error True on success, false or WP_Error on failure.
|
||||||
|
*/
|
||||||
|
public static function remove_follower( $user_id, $actor ) {
|
||||||
|
return wp_remove_object_terms( $user_id, $actor, self::TAXONOMY );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a Follower
|
||||||
|
*
|
||||||
|
* @param string $actor The Actor URL
|
||||||
|
* @return \Activitypub\Model\Follower The Follower object
|
||||||
|
*/
|
||||||
|
public static function get_follower( $actor ) {
|
||||||
|
$term = get_term_by( 'name', $actor, self::TAXONOMY );
|
||||||
|
|
||||||
|
return new Follower( $term->name );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send Accept response
|
||||||
|
*
|
||||||
|
* @param string $actor The Actor URL
|
||||||
|
* @param array $object The Activity object
|
||||||
|
* @param int $user_id The WordPress user_id
|
||||||
|
* @param Activitypub\Model\Follower $follower The Follower object
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public static function send_ack() {
|
public static function send_follow_response( $actor, $object, $user_id, $follower ) {
|
||||||
|
//if ( is_wp_error( $follower ) ) {
|
||||||
|
// @todo send error message
|
||||||
|
//}
|
||||||
|
|
||||||
// get inbox
|
// get inbox
|
||||||
$inbox = \Activitypub\get_inbox_by_actor( $object['actor'] );
|
$inbox = $follower->get_inbox();
|
||||||
|
|
||||||
// send "Accept" activity
|
// send "Accept" activity
|
||||||
$activity = new Activity( 'Accept' );
|
$activity = new Activity( 'Accept' );
|
||||||
$activity->set_object( $object );
|
$activity->set_object( $object );
|
||||||
$activity->set_actor( \get_author_posts_url( $user_id ) );
|
$activity->set_actor( \get_author_posts_url( $user_id ) );
|
||||||
$activity->set_to( $object['actor'] );
|
$activity->set_to( $actor );
|
||||||
$activity->set_id( \get_author_posts_url( $user_id ) . '#follow-' . \preg_replace( '~^https?://~', '', $object['actor'] ) );
|
$activity->set_id( \get_author_posts_url( $user_id ) . '#follow-' . \preg_replace( '~^https?://~', '', $actor ) );
|
||||||
|
|
||||||
$activity = $activity->to_simple_json();
|
$activity = $activity->to_simple_json();
|
||||||
$response = safe_remote_post( $inbox, $activity, $user_id );
|
$response = safe_remote_post( $inbox, $activity, $user_id );
|
||||||
|
@ -226,12 +218,13 @@ class Followers {
|
||||||
/**
|
/**
|
||||||
* Get the Followers of a given user
|
* Get the Followers of a given user
|
||||||
*
|
*
|
||||||
* @param int $user_id
|
* @param int $user_id The WordPress user_id
|
||||||
* @param int $number
|
* @param string $output The output format, supported ARRAY_N, OBJECT and ACTIVITYPUB_OBJECT
|
||||||
* @param int $offset
|
* @param int $number Limts the result
|
||||||
* @return array The Term list of Followers
|
* @param int $offset Offset
|
||||||
|
* @return array The Term list of Followers, the format depends on $output
|
||||||
*/
|
*/
|
||||||
public static function get_followers( $user_id, $number = null, $offset = null ) {
|
public static function get_followers( $user_id, $output = ARRAY_N, $number = null, $offset = null ) {
|
||||||
//self::migrate_followers( $user_id );
|
//self::migrate_followers( $user_id );
|
||||||
|
|
||||||
$terms = new WP_Term_Query(
|
$terms = new WP_Term_Query(
|
||||||
|
@ -244,7 +237,24 @@ class Followers {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return $terms->get_terms();
|
$items = array();
|
||||||
|
|
||||||
|
// change output format
|
||||||
|
switch ( $output ) {
|
||||||
|
case ACTIVITYPUB_OBJECT:
|
||||||
|
foreach ( $terms->get_terms() as $follower ) {
|
||||||
|
$items[] = new Follower( $follower->name ); // phpcs:ignore
|
||||||
|
}
|
||||||
|
return $items;
|
||||||
|
case OBJECT:
|
||||||
|
return $terms->get_terms();
|
||||||
|
case ARRAY_N:
|
||||||
|
default:
|
||||||
|
foreach ( $terms->get_terms() as $follower ) {
|
||||||
|
$items[] = $follower->name; // phpcs:ignore
|
||||||
|
}
|
||||||
|
return $items;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -257,6 +267,39 @@ class Followers {
|
||||||
return count( self::get_followers( $user_id ) );
|
return count( self::get_followers( $user_id ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function get_inboxes( $user_id ) {
|
||||||
|
// get all Followers of a WordPress user
|
||||||
|
$terms = new WP_Term_Query(
|
||||||
|
array(
|
||||||
|
'taxonomy' => self::TAXONOMY,
|
||||||
|
'hide_empty' => false,
|
||||||
|
'object_ids' => $user_id,
|
||||||
|
'fields' => 'ids',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$terms = $terms->get_terms();
|
||||||
|
|
||||||
|
global $wpdb;
|
||||||
|
$results = $wpdb->get_col(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"SELECT DISTINCT meta_value FROM {$wpdb->termmeta}
|
||||||
|
WHERE term_id IN (" . implode( ', ', array_fill( 0, count( $terms ), '%d' ) ) . ")
|
||||||
|
AND meta_key = 'shared_inbox'
|
||||||
|
AND meta_value IS NOT NULL",
|
||||||
|
$terms
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return array_filter( $results );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undocumented function
|
||||||
|
*
|
||||||
|
* @param [type] $user_id
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
public static function migrate_followers( $user_id ) {
|
public static function migrate_followers( $user_id ) {
|
||||||
$followes = get_user_meta( $user_id, 'activitypub_followers', true );
|
$followes = get_user_meta( $user_id, 'activitypub_followers', true );
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ function safe_remote_post( $url, $body, $user_id ) {
|
||||||
|
|
||||||
function safe_remote_get( $url, $user_id ) {
|
function safe_remote_get( $url, $user_id ) {
|
||||||
$date = \gmdate( 'D, d M Y H:i:s T' );
|
$date = \gmdate( 'D, d M Y H:i:s T' );
|
||||||
$signature = \Activitypub\Signature::generate_signature( $user_id, 'get', $url, $date );
|
$signature = Signature::generate_signature( $user_id, 'get', $url, $date );
|
||||||
|
|
||||||
$wp_version = \get_bloginfo( 'version' );
|
$wp_version = \get_bloginfo( 'version' );
|
||||||
$user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
|
$user_agent = \apply_filters( 'http_headers_useragent', 'WordPress/' . $wp_version . '; ' . \get_bloginfo( 'url' ) );
|
||||||
|
@ -95,15 +95,14 @@ function safe_remote_get( $url, $user_id ) {
|
||||||
* @return string The user-resource
|
* @return string The user-resource
|
||||||
*/
|
*/
|
||||||
function get_webfinger_resource( $user_id ) {
|
function get_webfinger_resource( $user_id ) {
|
||||||
return \Activitypub\Webfinger::get_user_resource( $user_id );
|
return Webfinger::get_user_resource( $user_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [get_metadata_by_actor description]
|
* Requests the Meta-Data from the Actors profile
|
||||||
*
|
*
|
||||||
* @param string $actor
|
* @param string $actor The Actor URL
|
||||||
*
|
* @return array The Actor profile as array
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
function get_remote_metadata_by_actor( $actor ) {
|
function get_remote_metadata_by_actor( $actor ) {
|
||||||
$pre = apply_filters( 'pre_get_remote_metadata_by_actor', false, $actor );
|
$pre = apply_filters( 'pre_get_remote_metadata_by_actor', false, $actor );
|
||||||
|
@ -165,82 +164,9 @@ function get_remote_metadata_by_actor( $actor ) {
|
||||||
return $metadata;
|
return $metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
\set_transient( $transient_key, $metadata, WEEK_IN_SECONDS );
|
|
||||||
|
|
||||||
return $metadata;
|
return $metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* [get_inbox_by_actor description]
|
|
||||||
* @param [type] $actor [description]
|
|
||||||
* @return [type] [description]
|
|
||||||
*/
|
|
||||||
function get_inbox_by_actor( $actor ) {
|
|
||||||
$metadata = \Activitypub\get_remote_metadata_by_actor( $actor );
|
|
||||||
|
|
||||||
if ( \is_wp_error( $metadata ) ) {
|
|
||||||
return $metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( isset( $metadata['endpoints'] ) && isset( $metadata['endpoints']['sharedInbox'] ) ) {
|
|
||||||
return $metadata['endpoints']['sharedInbox'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( \array_key_exists( 'inbox', $metadata ) ) {
|
|
||||||
return $metadata['inbox'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new \WP_Error( 'activitypub_no_inbox', \__( 'No "Inbox" found', 'activitypub' ), $metadata );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* [get_inbox_by_actor description]
|
|
||||||
* @param [type] $actor [description]
|
|
||||||
* @return [type] [description]
|
|
||||||
*/
|
|
||||||
function get_publickey_by_actor( $actor, $key_id ) {
|
|
||||||
$metadata = \Activitypub\get_remote_metadata_by_actor( $actor );
|
|
||||||
|
|
||||||
if ( \is_wp_error( $metadata ) ) {
|
|
||||||
return $metadata;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
isset( $metadata['publicKey'] ) &&
|
|
||||||
isset( $metadata['publicKey']['id'] ) &&
|
|
||||||
isset( $metadata['publicKey']['owner'] ) &&
|
|
||||||
isset( $metadata['publicKey']['publicKeyPem'] ) &&
|
|
||||||
$key_id === $metadata['publicKey']['id'] &&
|
|
||||||
$actor === $metadata['publicKey']['owner']
|
|
||||||
) {
|
|
||||||
return $metadata['publicKey']['publicKeyPem'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new \WP_Error( 'activitypub_no_public_key', \__( 'No "Public-Key" found', 'activitypub' ), $metadata );
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_follower_inboxes( $user_id, $cc = array() ) {
|
|
||||||
$followers = \Activitypub\Peer\Followers::get_followers( $user_id );
|
|
||||||
$followers = array_merge( $followers, $cc );
|
|
||||||
$followers = array_unique( $followers );
|
|
||||||
|
|
||||||
$inboxes = array();
|
|
||||||
|
|
||||||
foreach ( $followers as $follower ) {
|
|
||||||
$inbox = \Activitypub\get_inbox_by_actor( $follower );
|
|
||||||
if ( ! $inbox || \is_wp_error( $inbox ) ) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// init array if empty
|
|
||||||
if ( ! isset( $inboxes[ $inbox ] ) ) {
|
|
||||||
$inboxes[ $inbox ] = array();
|
|
||||||
}
|
|
||||||
$inboxes[ $inbox ][] = $follower;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $inboxes;
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_identifier_settings( $user_id ) {
|
function get_identifier_settings( $user_id ) {
|
||||||
?>
|
?>
|
||||||
<table class="form-table">
|
<table class="form-table">
|
||||||
|
@ -261,19 +187,11 @@ function get_identifier_settings( $user_id ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_followers( $user_id ) {
|
function get_followers( $user_id ) {
|
||||||
$followers = \Activitypub\Peer\Followers::get_followers( $user_id );
|
return Collection\Followers::get_followers( $user_id );
|
||||||
|
|
||||||
if ( ! $followers ) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $followers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function count_followers( $user_id ) {
|
function count_followers( $user_id ) {
|
||||||
$followers = \Activitypub\get_followers( $user_id );
|
return Collection\Followers::count_followers( $user_id );
|
||||||
|
|
||||||
return \count( $followers );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
187
includes/model/class-follower.php
Normal file
187
includes/model/class-follower.php
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
<?php
|
||||||
|
namespace Activitypub\Model;
|
||||||
|
|
||||||
|
use Activitypub\Collection\Followers;
|
||||||
|
|
||||||
|
use function Activitypub\get_remote_metadata_by_actor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ActivityPub Follower Class
|
||||||
|
*
|
||||||
|
* @author Matthias Pfefferle
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#follow-activity-inbox
|
||||||
|
*/
|
||||||
|
class Follower {
|
||||||
|
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
private $actor;
|
||||||
|
|
||||||
|
private $slug;
|
||||||
|
|
||||||
|
private $name;
|
||||||
|
|
||||||
|
private $username;
|
||||||
|
|
||||||
|
private $avatar;
|
||||||
|
|
||||||
|
private $inbox;
|
||||||
|
|
||||||
|
private $shared_inbox;
|
||||||
|
|
||||||
|
private $updated_at;
|
||||||
|
|
||||||
|
private $meta;
|
||||||
|
|
||||||
|
private $map_meta = array(
|
||||||
|
'name' => 'name',
|
||||||
|
'preferredUsername' => 'username',
|
||||||
|
'inbox' => 'inbox',
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param WP_Post $post
|
||||||
|
*/
|
||||||
|
public function __construct( $actor ) {
|
||||||
|
$term = get_term_by( 'name', $actor, Followers::TAXONOMY );
|
||||||
|
|
||||||
|
$this->actor = $actor;
|
||||||
|
|
||||||
|
if ( $term ) {
|
||||||
|
$this->id = $term->term_id;
|
||||||
|
$this->slug = $term->slug;
|
||||||
|
$this->meta = json_decode( $term->meta );
|
||||||
|
} else {
|
||||||
|
$this->slug = sanitize_title( $actor );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic function to implement getter and setter
|
||||||
|
*
|
||||||
|
* @param string $method
|
||||||
|
* @param string $params
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __call( $method, $params ) {
|
||||||
|
$var = \strtolower( \substr( $method, 4 ) );
|
||||||
|
|
||||||
|
if ( \strncasecmp( $method, 'get', 3 ) === 0 ) {
|
||||||
|
if ( empty( $this->$var ) ) {
|
||||||
|
return $this->get( $var );
|
||||||
|
}
|
||||||
|
return $this->$var;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
|
||||||
|
$this->$var = $params[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get( $attribute ) {
|
||||||
|
if ( $this->$attribute ) {
|
||||||
|
return $this->$attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! $this->id ) {
|
||||||
|
$this->$attribute = $this->get_meta_by( $attribute );
|
||||||
|
return $this->$attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->$attribute = get_term_meta( $this->id, $attribute, true );
|
||||||
|
return $this->$attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_meta_by( $attribute, $force = false ) {
|
||||||
|
$meta = $this->get_meta( $force );
|
||||||
|
|
||||||
|
foreach ( $this->map_meta as $remote => $local ) {
|
||||||
|
if ( $attribute === $local && isset( $meta[ $remote ] ) ) {
|
||||||
|
return $meta[ $remote ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_meta( $force = false ) {
|
||||||
|
if ( $this->meta && false === (bool) $force ) {
|
||||||
|
return $this->meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
$remote_data = get_remote_metadata_by_actor( $this->actor );
|
||||||
|
|
||||||
|
if ( ! $remote_data || is_wp_error( $remote_data ) || ! is_array( $remote_data ) ) {
|
||||||
|
$remote_data = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->meta = $remote_data;
|
||||||
|
|
||||||
|
return $this->meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update() {
|
||||||
|
$term = wp_update_term(
|
||||||
|
$this->id,
|
||||||
|
Followers::TAXONOMY,
|
||||||
|
array(
|
||||||
|
'description' => wp_json_encode( $this->get_meta( true ) ),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->update_term_meta();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save() {
|
||||||
|
$term = wp_insert_term(
|
||||||
|
$this->actor,
|
||||||
|
Followers::TAXONOMY,
|
||||||
|
array(
|
||||||
|
'slug' => sanitize_title( $this->get_actor() ),
|
||||||
|
'description' => wp_json_encode( $this->get_meta() ),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->id = $term['term_id'];
|
||||||
|
|
||||||
|
$this->update_term_meta();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function upsert() {
|
||||||
|
if ( $this->id ) {
|
||||||
|
$this->update();
|
||||||
|
} else {
|
||||||
|
$this->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function update_term_meta() {
|
||||||
|
$meta = $this->get_meta();
|
||||||
|
|
||||||
|
foreach ( $this->map_meta as $remote => $internal ) {
|
||||||
|
if ( ! empty( $meta[ $remote ] ) ) {
|
||||||
|
update_term_meta( $this->id, $internal, esc_html( $meta[ $remote ] ), true );
|
||||||
|
$this->$internal = $meta[ $remote ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $meta['icon']['url'] ) ) {
|
||||||
|
update_term_meta( $this->id, 'avatar', esc_url_raw( $meta['icon']['url'] ), true );
|
||||||
|
$this->avatar = $meta['icon']['url'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $meta['endpoints']['sharedInbox'] ) ) {
|
||||||
|
update_term_meta( $this->id, 'shared_inbox', esc_url_raw( $meta['endpoints']['sharedInbox'] ), true );
|
||||||
|
$this->shared_inbox = $meta['endpoints']['sharedInbox'];
|
||||||
|
} elseif ( ! empty( $meta['inbox'] ) ) {
|
||||||
|
update_term_meta( $this->id, 'shared_inbox', esc_url_raw( $meta['inbox'] ), true );
|
||||||
|
$this->shared_inbox = $meta['inbox'];
|
||||||
|
}
|
||||||
|
|
||||||
|
update_term_meta( $this->id, 'updated_at', \strtotime( 'now' ), true );
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,11 +11,7 @@ class Followers {
|
||||||
public static function get_followers( $author_id ) {
|
public static function get_followers( $author_id ) {
|
||||||
_deprecated_function( __METHOD__, '1.0.0', '\Activitypub\Collection\Followers::get_followers' );
|
_deprecated_function( __METHOD__, '1.0.0', '\Activitypub\Collection\Followers::get_followers' );
|
||||||
|
|
||||||
$items = array(); // phpcs:ignore
|
return \Activitypub\Collection\Followers::get_followers( $author_id );
|
||||||
foreach ( \Activitypub\Collection\Followers::get_followers( $author_id ) as $follower ) {
|
|
||||||
$items[] = $follower->name; // phpcs:ignore
|
|
||||||
}
|
|
||||||
return $items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function count_followers( $author_id ) {
|
public static function count_followers( $author_id ) {
|
||||||
|
|
|
@ -81,10 +81,7 @@ class Followers {
|
||||||
$json->partOf = \get_rest_url( null, "/activitypub/1.0/users/$user_id/followers" ); // phpcs:ignore
|
$json->partOf = \get_rest_url( null, "/activitypub/1.0/users/$user_id/followers" ); // phpcs:ignore
|
||||||
$json->first = $json->partOf; // phpcs:ignore
|
$json->first = $json->partOf; // phpcs:ignore
|
||||||
$json->totalItems = FollowerCollection::count_followers( $user_id ); // phpcs:ignore
|
$json->totalItems = FollowerCollection::count_followers( $user_id ); // phpcs:ignore
|
||||||
$json->orderedItems = array(); // phpcs:ignore
|
$json->orderedItems = FollowerCollection::get_followers( $user_id, ARRAY_N ); // phpcs:ignore
|
||||||
foreach ( FollowerCollection::get_followers( $user_id ) as $follower ) {
|
|
||||||
$json->orderedItems[] = $follower->name; // phpcs:ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
$response = new WP_REST_Response( $json, 200 );
|
$response = new WP_REST_Response( $json, 200 );
|
||||||
$response->header( 'Content-Type', 'application/activity+json' );
|
$response->header( 'Content-Type', 'application/activity+json' );
|
||||||
|
|
|
@ -17,8 +17,7 @@ class Inbox {
|
||||||
public static function init() {
|
public static function init() {
|
||||||
\add_action( 'rest_api_init', array( self::class, 'register_routes' ) );
|
\add_action( 'rest_api_init', array( self::class, 'register_routes' ) );
|
||||||
\add_filter( 'rest_pre_serve_request', array( self::class, 'serve_request' ), 11, 4 );
|
\add_filter( 'rest_pre_serve_request', array( self::class, 'serve_request' ), 11, 4 );
|
||||||
//\add_action( 'activitypub_inbox_like', array( self::class, 'handle_reaction' ), 10, 2 );
|
|
||||||
//\add_action( 'activitypub_inbox_announce', array( self::class, 'handle_reaction' ), 10, 2 );
|
|
||||||
\add_action( 'activitypub_inbox_create', array( self::class, 'handle_create' ), 10, 2 );
|
\add_action( 'activitypub_inbox_create', array( self::class, 'handle_create' ), 10, 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,43 +341,6 @@ class Inbox {
|
||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles "Follow" requests
|
|
||||||
*
|
|
||||||
* @param array $object The activity-object
|
|
||||||
* @param int $user_id The id of the local blog-user
|
|
||||||
*/
|
|
||||||
public static function handle_follow( $object, $user_id ) {
|
|
||||||
// save follower
|
|
||||||
\Activitypub\Peer\Followers::add_follower( $object['actor'], $user_id );
|
|
||||||
|
|
||||||
// get inbox
|
|
||||||
$inbox = \Activitypub\get_inbox_by_actor( $object['actor'] );
|
|
||||||
|
|
||||||
// send "Accept" activity
|
|
||||||
$activity = new Activity( 'Accept' );
|
|
||||||
$activity->set_object( $object );
|
|
||||||
$activity->set_actor( \get_author_posts_url( $user_id ) );
|
|
||||||
$activity->set_to( $object['actor'] );
|
|
||||||
$activity->set_id( \get_author_posts_url( $user_id ) . '#follow-' . \preg_replace( '~^https?://~', '', $object['actor'] ) );
|
|
||||||
|
|
||||||
$activity = $activity->to_simple_json();
|
|
||||||
|
|
||||||
$response = \Activitypub\safe_remote_post( $inbox, $activity, $user_id );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles "Unfollow" requests
|
|
||||||
*
|
|
||||||
* @param array $object The activity-object
|
|
||||||
* @param int $user_id The id of the local blog-user
|
|
||||||
*/
|
|
||||||
public static function handle_unfollow( $object, $user_id ) {
|
|
||||||
if ( isset( $object['object'] ) && isset( $object['object']['type'] ) && 'Follow' === $object['object']['type'] ) {
|
|
||||||
\Activitypub\Peer\Followers::remove_follower( $object['actor'], $user_id );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles "Reaction" requests
|
* Handles "Reaction" requests
|
||||||
*
|
*
|
||||||
|
|
|
@ -33,7 +33,7 @@ class Followers extends WP_List_Table {
|
||||||
$page_num = $this->get_pagenum();
|
$page_num = $this->get_pagenum();
|
||||||
$per_page = 20;
|
$per_page = 20;
|
||||||
|
|
||||||
$follower = FollowerCollection::get_followers( \get_current_user_id(), $per_page, ( $page_num - 1 ) * $per_page );
|
$follower = FollowerCollection::get_followers( \get_current_user_id(), ACTIVITYPUB_OBJECT, $per_page, ( $page_num - 1 ) * $per_page );
|
||||||
$counter = FollowerCollection::count_followers( \get_current_user_id() );
|
$counter = FollowerCollection::count_followers( \get_current_user_id() );
|
||||||
|
|
||||||
$this->items = array();
|
$this->items = array();
|
||||||
|
@ -47,10 +47,10 @@ class Followers extends WP_List_Table {
|
||||||
|
|
||||||
foreach ( $follower as $follower ) {
|
foreach ( $follower as $follower ) {
|
||||||
$item = array(
|
$item = array(
|
||||||
'avatar' => esc_attr( get_term_meta( $follower->term_id, 'avatar', true ) ),
|
'avatar' => esc_attr( $follower->get_avatar() ),
|
||||||
'name' => esc_attr( get_term_meta( $follower->term_id, 'name', true ) ),
|
'name' => esc_attr( $follower->get_name() ),
|
||||||
'username' => esc_attr( get_term_meta( $follower->term_id, 'username', true ) ),
|
'username' => esc_attr( $follower->get_username() ),
|
||||||
'identifier' => esc_attr( $follower->name ),
|
'identifier' => esc_attr( $follower->get_actor() ),
|
||||||
);
|
);
|
||||||
|
|
||||||
$this->items[] = $item;
|
$this->items[] = $item;
|
||||||
|
|
Loading…
Reference in a new issue