use transformer instead of post-model

This commit is contained in:
Matthias Pfefferle 2023-07-03 17:59:42 +02:00
parent 359eabf671
commit 493b8ffad5
21 changed files with 282 additions and 690 deletions

View file

@ -7,6 +7,8 @@
namespace Activitypub\Activity; namespace Activitypub\Activity;
use Activitypub\Activity\Base_Object;
/** /**
* \Activitypub\Activity\Activity implements the common * \Activitypub\Activity\Activity implements the common
* attributes of an Activity. * attributes of an Activity.
@ -162,4 +164,40 @@ class Activity extends Base_Object {
* | null * | null
*/ */
protected $instrument; protected $instrument;
/**
* Set the object and copy Object properties to the Activity.
*
* Any to, bto, cc, bcc, and audience properties specified on the object
* MUST be copied over to the new Create activity by the server.
*
* @see https://www.w3.org/TR/activitypub/#object-without-create
*
* @param \Activitypub\Activity\Base_Object $object
*
* @return void
*/
public function set_object( Base_Object $object ) {
parent::set_object( $object );
foreach ( array( 'to', 'bto', 'cc', 'bcc', 'audience' ) as $i ) {
$this->set( $i, $object->get( $i ) );
}
if ( $object->get_published() && ! $this->get_published() ) {
$this->set( 'published', $object->get_published() );
}
if ( $object->get_updated() && ! $this->get_updated() ) {
$this->set( 'updated', $object->get_updated() );
}
if ( $object->attributed_to() && ! $this->get_actor() ) {
$this->set( 'actor', $object->attributed_to() );
}
if ( $object->get_id() && ! $this->get_id() ) {
$this->set( 'id', $object->get_id() . '#activity' );
}
}
} }

View file

@ -604,6 +604,10 @@ class Base_Object {
$value = call_user_func( array( $this, 'get_' . $key ) ); $value = call_user_func( array( $this, 'get_' . $key ) );
} }
if ( is_object( $value ) ) {
$value = $value->to_array();
}
// if value is still empty, ignore it for the array and continue. // if value is still empty, ignore it for the array and continue.
if ( isset( $value ) ) { if ( isset( $value ) ) {
$array[ snake_to_camel_case( $key ) ] = $value; $array[ snake_to_camel_case( $key ) ] = $value;
@ -625,4 +629,15 @@ class Base_Object {
return $array; return $array;
} }
/**
* Convert Object to JSON.
*
* @return string The JSON string.
*/
public function to_json() {
$array = $this->to_array();
return \wp_json_encode( $array );
}
} }

View file

@ -1,10 +1,11 @@
<?php <?php
namespace Activitypub; namespace Activitypub;
use Activitypub\Model\Post; use WP_Post;
use Activitypub\Model\Activity; use Activitypub\Activity\Activity;
use Activitypub\Collection\Users; use Activitypub\Collection\Users;
use Activitypub\Collection\Followers; use Activitypub\Collection\Followers;
use Activitypub\Transformer\Post;
use function Activitypub\safe_remote_post; use function Activitypub\safe_remote_post;
@ -23,66 +24,73 @@ class Activity_Dispatcher {
// legacy // legacy
\add_action( 'activitypub_send_post_activity', array( self::class, 'send_create_activity' ) ); \add_action( 'activitypub_send_post_activity', array( self::class, 'send_create_activity' ) );
\add_action( 'activitypub_send_create_activity', array( self::class, 'send_create_activity' ) ); \add_action( 'activitypub_send_activity', array( self::class, 'send_user_activity' ), 10, 2 );
\add_action( 'activitypub_send_update_activity', array( self::class, 'send_update_activity' ) ); \add_action( 'activitypub_send_activity', array( self::class, 'send_blog_activity' ), 10, 2 );
\add_action( 'activitypub_send_delete_activity', array( self::class, 'send_delete_activity' ) );
\add_action( 'activitypub_send_activity', array( self::class, 'send_activity' ), 10, 2 );
}
/**
* Send "create" activities.
*
* @param Activitypub\Model\Post $activitypub_post
*/
public static function send_create_activity( Post $activitypub_post ) {
self::send_activity( $activitypub_post, 'Create' );
}
/**
* Send "update" activities.
*
* @param Activitypub\Model\Post $activitypub_post The ActivityPub Post.
*/
public static function send_update_activity( Post $activitypub_post ) {
self::send_activity( $activitypub_post, 'Update' );
}
/**
* Send "delete" activities.
*
* @param Activitypub\Model\Post $activitypub_post The ActivityPub Post.
*/
public static function send_delete_activity( Post $activitypub_post ) {
self::send_activity( $activitypub_post, 'Delete' );
} }
/** /**
* Send Activities to followers and mentioned users. * Send Activities to followers and mentioned users.
* *
* @param Activitypub\Model\Post $activitypub_post The ActivityPub Post. * @param WP_Post $post The ActivityPub Post.
* @param string $activity_type The Activity-Type. * @param string $type The Activity-Type.
* *
* @return void * @return void
*/ */
public static function send_activity( Post $activitypub_post, $activity_type ) { public static function send_user_activity( WP_Post $post, $type ) {
// check if a migration is needed before sending new posts // check if a migration is needed before sending new posts
Migration::maybe_migrate(); Migration::maybe_migrate();
$activitypub_activity = new Activity( $activity_type ); $object = Post::transform( $post )->to_object();
$activitypub_activity->from_post( $activitypub_post );
$user_id = $activitypub_post->get_user_id(); $activity = new Activity();
$activity->set_type( $type );
$activity->set_object( $object );
$user_id = $post->post_author;
$follower_inboxes = Followers::get_inboxes( $user_id ); $follower_inboxes = Followers::get_inboxes( $user_id );
$mentioned_inboxes = Mention::get_inboxes( $activitypub_activity->get_cc() ); $mentioned_inboxes = Mention::get_inboxes( $activity->get_cc() );
$inboxes = array_merge( $follower_inboxes, $mentioned_inboxes ); $inboxes = array_merge( $follower_inboxes, $mentioned_inboxes );
$inboxes = array_unique( $inboxes ); $inboxes = array_unique( $inboxes );
foreach ( $inboxes as $inbox ) { $array = $activity->to_json();
$activity = $activitypub_activity->to_json();
safe_remote_post( $inbox, $activity, $user_id ); foreach ( $inboxes as $inbox ) {
safe_remote_post( $inbox, $array, $user_id );
}
}
/**
* Send Activities to followers and mentioned users.
*
* @param WP_Post $post The ActivityPub Post.
* @param string $type The Activity-Type.
*
* @return void
*/
public static function send_blog_activity( WP_Post $post, $type ) {
// check if a migration is needed before sending new posts
Migration::maybe_migrate();
$user = Users::get_by_id( Users::BLOG_USER_ID );
$object = Post::transform( $post )->to_object();
$object->set_attributed_to( $user->get_url() );
$activity = new Activity();
$activity->set_type( $type );
$activity->set_object( $object );
$follower_inboxes = Followers::get_inboxes( $user->get__id() );
$mentioned_inboxes = Mention::get_inboxes( $activity->get_cc() );
$inboxes = array_merge( $follower_inboxes, $mentioned_inboxes );
$inboxes = array_unique( $inboxes );
$array = $activity->to_array();
foreach ( $inboxes as $inbox ) {
safe_remote_post( $inbox, $array, $user_id );
} }
} }
} }

View file

@ -2,6 +2,7 @@
namespace Activitypub; namespace Activitypub;
use Activitypub\Signature; use Activitypub\Signature;
use Activitypub\Collection\Users;
/** /**
* ActivityPub Class * ActivityPub Class

View file

@ -1,8 +1,6 @@
<?php <?php
namespace Activitypub; namespace Activitypub;
use Activitypub\Model\Post;
/** /**
* ActivityPub Admin Class * ActivityPub Admin Class
* *

View file

@ -2,9 +2,9 @@
namespace Activitypub; namespace Activitypub;
use Activitypub\Model\Post;
use Activitypub\Collection\Users; use Activitypub\Collection\Users;
use Activitypub\Collection\Followers; use Activitypub\Collection\Followers;
use \Activitypub\Transformer\Post;
/** /**
* ActivityPub Scheduler Class * ActivityPub Scheduler Class
@ -83,12 +83,10 @@ class Scheduler {
return; return;
} }
$activitypub_post = new Post( $post );
\wp_schedule_single_event( \wp_schedule_single_event(
\time(), \time(),
'activitypub_send_activity', 'activitypub_send_activity',
array( $activitypub_post, $type ) array( $post, $type )
); );
\wp_schedule_single_event( \wp_schedule_single_event(
@ -97,7 +95,7 @@ class Scheduler {
'activitypub_send_%s_activity', 'activitypub_send_%s_activity',
\strtolower( $type ) \strtolower( $type )
), ),
array( $activitypub_post ) array( $post )
); );
} }

View file

@ -6,8 +6,8 @@ use Exception;
use WP_Query; use WP_Query;
use Activitypub\Http; use Activitypub\Http;
use Activitypub\Webfinger; use Activitypub\Webfinger;
use Activitypub\Model\Activity;
use Activitypub\Model\Follower; use Activitypub\Model\Follower;
use Activitypub\Activity\Activity;
use function Activitypub\is_tombstone; use function Activitypub\is_tombstone;
use function Activitypub\get_remote_metadata_by_actor; use function Activitypub\get_remote_metadata_by_actor;

View file

@ -1,244 +0,0 @@
<?php
namespace Activitypub\Model;
use function Activitypub\get_rest_url_by_path;
/**
* ActivityPub Post Class
*
* @author Matthias Pfefferle
*
* @see https://www.w3.org/TR/activitypub/
*/
class Activity {
const CONTEXT = array(
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
array(
'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers',
'PropertyValue' => 'schema:PropertyValue',
'schema' => 'http://schema.org#',
'pt' => 'https://joinpeertube.org/ns#',
'toot' => 'http://joinmastodon.org/ns#',
'value' => 'schema:value',
'Hashtag' => 'as:Hashtag',
'featured' => array(
'@id' => 'toot:featured',
'@type' => '@id',
),
'featuredTags' => array(
'@id' => 'toot:featuredTags',
'@type' => '@id',
),
),
);
/**
* The JSON-LD context.
*
* @var array
*/
private $context = self::CONTEXT;
/**
* The published date.
*
* @var string
*/
private $published = '';
/**
* The Activity-ID.
*
* @var string
*/
private $id = '';
/**
* The Activity-Type.
*
* @var string
*/
private $type = 'Create';
/**
* The Activity-Actor.
*
* @var string
*/
private $actor = '';
/**
* The Audience.
*
* @var array
*/
private $to = array( 'https://www.w3.org/ns/activitystreams#Public' );
/**
* The CC.
*
* @var array
*/
private $cc = array();
/**
* The Activity-Object.
*
* @var array
*/
private $object = null;
/**
* The Class-Constructor.
*
* @param string $type The Activity-Type.
* @param boolean $context The JSON-LD context.
*/
public function __construct( $type = 'Create', $context = true ) {
if ( true !== $context ) {
$this->context = null;
}
$this->type = \ucfirst( $type );
$this->published = \gmdate( 'Y-m-d\TH:i:s\Z', \time() );
}
/**
* Magic Getter/Setter
*
* @param string $method The method name.
* @param string $params The method params.
*
* @return mixed The value.
*/
public function __call( $method, $params ) {
$var = \strtolower( \substr( $method, 4 ) );
if ( \strncasecmp( $method, 'get', 3 ) === 0 ) {
return $this->$var;
}
if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
$this->$var = $params[0];
}
if ( \strncasecmp( $method, 'add', 3 ) === 0 ) {
if ( ! is_array( $this->$var ) ) {
$this->$var = $params[0];
}
if ( is_array( $params[0] ) ) {
$this->$var = array_merge( $this->$var, $params[0] );
} else {
array_push( $this->$var, $params[0] );
}
$this->$var = array_unique( $this->$var );
}
}
/**
* Convert from a Post-Object.
*
* @param Post $post The Post-Object.
*
* @return void
*/
public function from_post( Post $post ) {
$this->object = $post->to_array();
if ( isset( $object['published'] ) ) {
$this->published = $object['published'];
}
$path = sprintf( 'users/%d/followers', intval( $post->get_post_author() ) );
$this->add_to( get_rest_url_by_path( $path ) );
if ( isset( $this->object['attributedTo'] ) ) {
$this->actor = $this->object['attributedTo'];
}
foreach ( $post->get_tags() as $tag ) {
if ( 'Mention' === $tag['type'] ) {
$this->add_cc( $tag['href'] );
}
}
$type = \strtolower( $this->type );
if ( isset( $this->object['id'] ) ) {
$this->id = add_query_arg( 'activity', $type, $this->object['id'] );
}
}
public function from_comment( $object ) {
}
public function to_comment() {
}
public function from_remote_array( $array ) {
}
/**
* Convert to an Array.
*
* @return array The Array.
*/
public function to_array() {
$array = array_filter( \get_object_vars( $this ) );
if ( $this->context ) {
$array = array( '@context' => $this->context ) + $array;
}
unset( $array['context'] );
return $array;
}
/**
* Convert to JSON
*
* @return string The JSON.
*/
public function to_json() {
return \wp_json_encode( $this->to_array(), \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT );
}
/**
* Convert to a Simple Array.
*
* @return string The array.
*/
public function to_simple_array() {
$activity = array(
'@context' => $this->context,
'type' => $this->type,
'actor' => $this->actor,
'object' => $this->object,
'to' => $this->to,
'cc' => $this->cc,
);
if ( $this->id ) {
$activity['id'] = $this->id;
}
return $activity;
}
/**
* Convert to a Simple JSON.
*
* @return string The JSON.
*/
public function to_simple_json() {
return \wp_json_encode( $this->to_simple_array(), \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT );
}
}

View file

@ -4,7 +4,6 @@ namespace Activitypub\Model;
use WP_Query; use WP_Query;
use WP_Error; use WP_Error;
use Activitypub\Signature; use Activitypub\Signature;
use Activitypub\Model\User;
use Activitypub\Collection\Users; use Activitypub\Collection\Users;
use Activitypub\Activity\Actor; use Activitypub\Activity\Actor;

View file

@ -5,7 +5,7 @@ use WP_Error;
use WP_REST_Server; use WP_REST_Server;
use WP_REST_Response; use WP_REST_Response;
use Activitypub\Collection\Users; use Activitypub\Collection\Users;
use Activitypub\Model\Activity; use Activitypub\Activity\Activity;
use function Activitypub\get_context; use function Activitypub\get_context;
use function Activitypub\url_to_authorid; use function Activitypub\url_to_authorid;

View file

@ -5,9 +5,9 @@ use stdClass;
use WP_Error; use WP_Error;
use WP_REST_Server; use WP_REST_Server;
use WP_REST_Response; use WP_REST_Response;
use Activitypub\Activity\Activity;
use Activitypub\Collection\Users; use Activitypub\Collection\Users;
use Activitypub\Model\Post; use Activitypub\Transformer\Post;
use Activitypub\Model\Activity;
use function Activitypub\get_context; use function Activitypub\get_context;
use function Activitypub\get_rest_url_by_path; use function Activitypub\get_rest_url_by_path;
@ -73,9 +73,9 @@ class Outbox {
$json->{'@context'} = get_context(); $json->{'@context'} = get_context();
$json->id = \home_url( \add_query_arg( null, null ) ); $json->id = \home_url( \add_query_arg( null, null ) );
$json->generator = 'http://wordpress.org/?v=' . \get_bloginfo_rss( 'version' ); $json->generator = 'http://wordpress.org/?v=' . \get_bloginfo_rss( 'version' );
$json->actor = $user->get_id(); //$json->actor = $user->get_id();
$json->type = 'OrderedCollectionPage'; $json->type = 'OrderedCollectionPage';
$json->partOf = get_rest_url_by_path( sprintf( 'users/%d/outbox', $user->get__id() ) ); // phpcs:ignore $json->partOf = get_rest_url_by_path( sprintf( 'users/%d/outbox', $user_id ) ); // phpcs:ignore
$json->totalItems = 0; // phpcs:ignore $json->totalItems = 0; // phpcs:ignore
// phpcs:ignore // phpcs:ignore
@ -97,18 +97,20 @@ class Outbox {
$posts = \get_posts( $posts = \get_posts(
array( array(
'posts_per_page' => 10, 'posts_per_page' => 10,
'author' => $user->get__id(), 'author' => $user_id,
'offset' => ( $page - 1 ) * 10, 'offset' => ( $page - 1 ) * 10,
'post_type' => $post_types, 'post_type' => $post_types,
) )
); );
foreach ( $posts as $post ) { foreach ( $posts as $post ) {
$activitypub_post = new Post( $post ); $post = Post::transform( $post )->to_object();
$activitypub_activity = new Activity( 'Create', false ); $activity = new Activity();
$activity->set_type( 'Create' );
$activity->set_context( null );
$activity->set_object( $post );
$activitypub_activity->from_post( $activitypub_post ); $json->orderedItems[] = $activity->to_array(); // phpcs:ignore
$json->orderedItems[] = $activitypub_activity->to_array(); // phpcs:ignore
} }
} }

View file

@ -4,8 +4,8 @@ namespace Activitypub\Rest;
use WP_Error; use WP_Error;
use WP_REST_Server; use WP_REST_Server;
use WP_REST_Response; use WP_REST_Response;
use \Activitypub\Model\Activity; use \Activitypub\Activity\Activity;
use Activitypub\Collection\User_Collection; use Activitypub\Collection\Users as User_Collection;
use function Activitypub\is_activitypub_request; use function Activitypub\is_activitypub_request;

View file

@ -1,84 +1,37 @@
<?php <?php
namespace Activitypub\Model; namespace Activitypub\Transformer;
use WP_Post;
use \Activitypub\Activity\Base_Object;
use \Activitypub\Collection\Users;
use Activitypub\Collection\Users;
use function Activitypub\get_rest_url_by_path; use function Activitypub\get_rest_url_by_path;
/** /**
* ActivityPub Post Class * WordPress Post Transformer
* *
* @author Matthias Pfefferle * The Post Transformer is responsible for transforming a WP_Post object into different othe
* Object-Types.
*
* Currently supported are:
*
* - Activitypub\Activity\Base_Object
*/ */
class Post { class Post {
/** /**
* The WordPress Post Object. * The WP_Post object.
* *
* @var WP_Post * @var WP_Post
*/ */
private $post; protected $wp_post;
/**
* The Post Author.
*
* @var string
*/
private $post_author;
/**
* The Object ID.
*
* @var string
*/
private $id;
/**
* The Object URL.
*
* @var string
*/
private $url;
/**
* The Object Summary.
*
* @var string
*/
private $summary;
/**
* The Object Summary
*
* @var string
*/
private $content;
/**
* The Object Attachments. This is usually a list of Images.
*
* @var array
*/
private $attachments;
/**
* The Object Tags. This is usually the list of used Hashtags.
*
* @var array
*/
private $tags;
/**
* The Onject Type
*
* @var string
*/
private $object_type;
/** /**
* The Allowed Tags, used in the content. * The Allowed Tags, used in the content.
* *
* @var array * @var array
*/ */
private $allowed_tags = array( protected $allowed_tags = array(
'a' => array( 'a' => array(
'href' => array(), 'href' => array(),
'title' => array(), 'title' => array(),
@ -126,185 +79,70 @@ class Post {
); );
/** /**
* List of audience * Static function to Transform a WP_Post Object.
* *
* Also used for visibility * This helps to chain the output of the Transformer.
* *
* @var array * @param WP_Post $wp_post The WP_Post object
*/
private $to = array( 'https://www.w3.org/ns/activitystreams#Public' );
/**
* List of audience
*
* Also used for visibility
*
* @var array
*/
private $cc = array();
/**
* Constructor
*
* @param WP_Post $post
* @param int $post_author
*/
public function __construct( $post, $post_author = null ) {
$this->post = \get_post( $post );
if ( $post_author ) {
$this->post_author = $post_author;
} else {
$this->post_author = $this->post->post_author;
}
$path = sprintf( 'users/%d/followers', intval( $this->get_post_author() ) );
$this->add_to( get_rest_url_by_path( $path ) );
}
/**
* Magic function to implement getter and setter
*
* @param string $method
* @param string $params
* *
* @return void * @return void
*/ */
public function __call( $method, $params ) { public static function transform( WP_Post $wp_post ) {
$var = \strtolower( \substr( $method, 4 ) ); return new self( $wp_post );
if ( \strncasecmp( $method, 'get', 3 ) === 0 ) {
if ( empty( $this->$var ) && ! empty( $this->post->$var ) ) {
return $this->post->$var;
}
return $this->$var;
}
if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
$this->$var = $params[0];
}
if ( \strncasecmp( $method, 'add', 3 ) === 0 ) {
if ( ! is_array( $this->$var ) ) {
$this->$var = $params[0];
}
if ( is_array( $params[0] ) ) {
$this->$var = array_merge( $this->$var, $params[0] );
} else {
array_push( $this->$var, $params[0] );
}
$this->$var = array_unique( $this->$var );
}
} }
/** /**
* Returns the User ID.
* *
* @return int the User ID. *
* @param WP_Post $wp_post
*/ */
public function get_user_id() { public function __construct( WP_Post $wp_post ) {
return apply_filters( 'activitypub_post_user_id', $this->get_post_author(), $this->post ); $this->wp_post = $wp_post;
} }
/** /**
* Converts this Object into an Array. * Transforms the WP_Post object to an ActivityPub Object
* *
* @return array the array representation of a Post. * @see \Activitypub\Activity\Base_Object
*
* @return \Activitypub\Activity\Base_Object The ActivityPub Object
*/ */
public function to_array() { public function to_object() {
$post = $this->post; $wp_post = $this->wp_post;
$object = new Base_Object();
$array = array( $object->set_id( \esc_url( \get_permalink( $wp_post->ID ) ) );
'id' => $this->get_id(), $object->set_url( \esc_url( \get_permalink( $wp_post->ID ) ) );
'url' => $this->get_url(), $object->set_type( $this->get_object_type() );
'type' => $this->get_object_type(), $object->set_published( \gmdate( 'Y-m-d\TH:i:s\Z', \strtotime( $wp_post->post_date_gmt ) ) );
'published' => \gmdate( 'Y-m-d\TH:i:s\Z', \strtotime( $post->post_date_gmt ) ), $object->attributed_to( Users::get_by_id( $wp_post->post_author )->get_url() );
'attributedTo' => $this->get_actor(), $object->set_content( $this->get_content() );
'summary' => $this->get_summary(), $object->set_content_map(
'inReplyTo' => null, array(
'content' => $this->get_content(),
'contentMap' => array(
\strstr( \get_locale(), '_', true ) => $this->get_content(), \strstr( \get_locale(), '_', true ) => $this->get_content(),
), )
'to' => $this->get_to(),
'cc' => $this->get_cc(),
'attachment' => $this->get_attachments(),
'tag' => $this->get_tags(),
); );
$path = sprintf( 'users/%d/followers', intval( $wp_post->post_author ) );
return \apply_filters( 'activitypub_post', $array, $this->post ); $object->set_to(
array(
'https://www.w3.org/ns/activitystreams#Public',
get_rest_url_by_path( $path ),
)
);
$object->set_cc( $this->get_cc() );
$object->set_attachment( $this->get_attachments() );
$object->set_tag( $this->get_tags() );
return $object;
} }
/** /**
* Returns the Actor of this Object. * Generates all Image Attachments for a Post.
* *
* @return string The URL of the Actor. * @return array The Image Attachments.
*/ */
public function get_actor() { protected function get_attachments() {
$user = Users::get_by_id( $this->get_user_id() );
return $user->get_url();
}
/**
* Converts this Object into a JSON String
*
* @return string
*/
public function to_json() {
return \wp_json_encode( $this->to_array(), \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT );
}
/**
* Returns the URL of an Activity Object
*
* @return string
*/
public function get_url() {
if ( $this->url ) {
return $this->url;
}
$post = $this->post;
if ( 'trash' === get_post_status( $post ) ) {
$permalink = \get_post_meta( $post->ID, 'activitypub_canonical_url', true );
} else {
$permalink = \get_permalink( $post );
}
$this->url = $permalink;
return $permalink;
}
/**
* Returns the ID of an Activity Object
*
* @return string
*/
public function get_id() {
if ( $this->id ) {
return $this->id;
}
$this->id = $this->get_url();
return $this->id;
}
/**
* Returns a list of Image Attachments
*
* @return array
*/
public function get_attachments() {
if ( $this->attachments ) {
return $this->attachments;
}
$max_images = intval( \apply_filters( 'activitypub_max_image_attachments', \get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ) ) ); $max_images = intval( \apply_filters( 'activitypub_max_image_attachments', \get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ) ) );
$images = array(); $images = array();
@ -314,7 +152,7 @@ class Post {
return $images; return $images;
} }
$id = $this->post->ID; $id = $this->wp_post->ID;
$image_ids = array(); $image_ids = array();
@ -393,7 +231,7 @@ class Post {
* *
* @return array|false Array of image data, or boolean false if no image is available. * @return array|false Array of image data, or boolean false if no image is available.
*/ */
public function get_image( $id, $image_size = 'full' ) { protected function get_image( $id, $image_size = 'full' ) {
/** /**
* Hook into the image retrieval process. Before image retrieval. * Hook into the image retrieval process. Before image retrieval.
* *
@ -416,64 +254,22 @@ class Post {
} }
/** /**
* Returns a list of Tags, used in the Post * Returns the ActivityStreams 2.0 Object-Type for a Post based on the
* settings and the Post-Type.
* *
* @return array * @see https://www.w3.org/TR/activitystreams-vocabulary/#activity-types
*/
public function get_tags() {
if ( $this->tags ) {
return $this->tags;
}
$tags = array();
$post_tags = \get_the_tags( $this->post->ID );
if ( $post_tags ) {
foreach ( $post_tags as $post_tag ) {
$tag = array(
'type' => 'Hashtag',
'href' => \get_tag_link( $post_tag->term_id ),
'name' => '#' . $post_tag->slug,
);
$tags[] = $tag;
}
}
$mentions = apply_filters( 'activitypub_extract_mentions', array(), $this->post->post_content, $this );
if ( $mentions ) {
foreach ( $mentions as $mention => $url ) {
$tag = array(
'type' => 'Mention',
'href' => $url,
'name' => $mention,
);
$tags[] = $tag;
}
}
$this->tags = $tags;
return $tags;
}
/**
* Returns the as2 object-type for a given post
* *
* @return string the object-type * @return string The Object-Type.
*/ */
public function get_object_type() { protected function get_object_type() {
if ( $this->object_type ) {
return $this->object_type;
}
if ( 'wordpress-post-format' !== \get_option( 'activitypub_object_type', 'note' ) ) { if ( 'wordpress-post-format' !== \get_option( 'activitypub_object_type', 'note' ) ) {
return \ucfirst( \get_option( 'activitypub_object_type', 'note' ) ); return \ucfirst( \get_option( 'activitypub_object_type', 'note' ) );
} }
$post_type = \get_post_type( $this->post ); $post_type = \get_post_type( $this->wp_post );
switch ( $post_type ) { switch ( $post_type ) {
case 'post': case 'post':
$post_format = \get_post_format( $this->post ); $post_format = \get_post_format( $this->wp_post );
switch ( $post_format ) { switch ( $post_format ) {
case 'aside': case 'aside':
case 'status': case 'status':
@ -519,25 +315,78 @@ class Post {
break; break;
} }
$this->object_type = $object_type;
return $object_type; return $object_type;
} }
/**
* Returns a list of Mentions, used in the Post.
*
* @see https://docs.joinmastodon.org/spec/activitypub/#Mention
*
* @return array The list of Mentions.
*/
protected function get_cc() {
$cc = array();
$mentions = $this->get_mentions();
if ( $mentions ) {
foreach ( $mentions as $mention => $url ) {
$cc[] = $url;
}
}
return $cc;
}
/**
* Returns a list of Tags, used in the Post.
*
* This includes Hash-Tags and Mentions.
*
* @return array The list of Tags.
*/
protected function get_tags() {
$tags = array();
$post_tags = \get_the_tags( $this->wp_post->ID );
if ( $post_tags ) {
foreach ( $post_tags as $post_tag ) {
$tag = array(
'type' => 'Hashtag',
'href' => esc_url( \get_tag_link( $post_tag->term_id ) ),
'name' => '#' . \esc_attr( $post_tag->slug ),
);
$tags[] = $tag;
}
}
$mentions = $this->get_mentions();
if ( $mentions ) {
foreach ( $mentions as $mention => $url ) {
$tag = array(
'type' => 'Mention',
'href' => \esc_url( $url ),
'name' => \esc_html( $mention ),
);
$tags[] = $tag;
}
}
return $tags;
}
/** /**
* Returns the content for the ActivityPub Item. * Returns the content for the ActivityPub Item.
* *
* @return string the content * The content will be generated based on the user settings.
*
* @return string The content.
*/ */
public function get_content() { protected function get_content() {
global $post; global $post;
if ( $this->content ) {
return $this->content;
}
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$post = $this->post; $post = $this->wp_post;
$content = $this->get_post_content_template(); $content = $this->get_post_content_template();
// Fill in the shortcodes. // Fill in the shortcodes.
@ -553,17 +402,15 @@ class Post {
$content = \apply_filters( 'activitypub_the_content', $content, $post ); $content = \apply_filters( 'activitypub_the_content', $content, $post );
$content = \html_entity_decode( $content, \ENT_QUOTES, 'UTF-8' ); $content = \html_entity_decode( $content, \ENT_QUOTES, 'UTF-8' );
$this->content = $content;
return $content; return $content;
} }
/** /**
* Gets the template to use to generate the content of the activitypub item. * Gets the template to use to generate the content of the activitypub item.
* *
* @return string the template * @return string The Template.
*/ */
public function get_post_content_template() { protected function get_post_content_template() {
if ( 'excerpt' === \get_option( 'activitypub_post_content_type', 'content' ) ) { if ( 'excerpt' === \get_option( 'activitypub_post_content_type', 'content' ) ) {
return "[ap_excerpt]\n\n[ap_permalink type=\"html\"]"; return "[ap_excerpt]\n\n[ap_permalink type=\"html\"]";
} }
@ -578,4 +425,13 @@ class Post {
return \get_option( 'activitypub_custom_post_content', ACTIVITYPUB_CUSTOM_POST_CONTENT ); return \get_option( 'activitypub_custom_post_content', ACTIVITYPUB_CUSTOM_POST_CONTENT );
} }
/**
* Helper function to get the @-Mentions from the post content.
*
* @return array The list of @-Mentions.
*/
protected function get_mentions() {
return apply_filters( 'activitypub_extract_mentions', array(), $this->wp_post->post_content, $this->wp_post );
}
} }

View file

@ -1,76 +0,0 @@
<?php
namespace Activitypub\Transformer;
use \Activitypub\Model\User;
use function Activitypub\is_user_disabled;
use function Activitypub\get_rest_url_by_path;
class Wp_User {
protected $wp_user;
public function construct( WP_User $wp_user ) {
$this->wp_user = $wp_user;
}
public function to_user() {
$wp_user = $this->wp_user;
if (
is_user_disabled( $user->ID ) ||
! get_user_by( 'id', $user->ID )
) {
return new WP_Error(
'activitypub_user_not_found',
\__( 'User not found', 'activitypub' ),
array( 'status' => 404 )
);
}
$user = new User();
$user->setwp_user->ID( \esc_url( \get_author_posts_url( $wp_user->ID ) ) );
$user->set_url( \esc_url( \get_author_posts_url( $wp_user->ID ) ) );
$user->set_summary( $this->get_summary() );
$user->set_name( \esc_attr( $wp_user->display_name ) );
$user->set_preferred_username( \esc_attr( $wp_user->login ) );
$user->set_icon( $this->get_icon() );
$user->set_image( $this->get_image() );
return $user;
}
public function get_summary() {
$description = get_user_meta( $this->wp_user->ID, 'activitypub_user_description', true );
if ( empty( $description ) ) {
$description = $this->wp_user->description;
}
return \wpautop( \wp_kses( $description, 'default' ) );
}
public function get_icon() {
$icon = \esc_url(
\get_avatar_url(
$this->wp_user->ID,
array( 'size' => 120 )
)
);
return array(
'type' => 'Image',
'url' => $icon,
);
}
public function get_image() {
if ( \has_header_image() ) {
$image = \esc_url( \get_header_image() );
return array(
'type' => 'Image',
'url' => $image,
);
}
return null;
}
}

View file

@ -2,7 +2,7 @@
$user = \Activitypub\Collection\Users::get_by_id( \get_the_author_meta( 'ID' ) ); $user = \Activitypub\Collection\Users::get_by_id( \get_the_author_meta( 'ID' ) );
$user->set_context( $user->set_context(
\Activitypub\Model\Activity::CONTEXT \Activitypub\Activity\Activity::CONTEXT
); );
/* /*

View file

@ -2,7 +2,7 @@
$user = new \Activitypub\Model\Blog_User(); $user = new \Activitypub\Model\Blog_User();
$user->set_context( $user->set_context(
\Activitypub\Model\Activity::CONTEXT \Activitypub\Activity\Activity::CONTEXT
); );
/* /*

View file

@ -2,8 +2,8 @@
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$post = \get_post(); $post = \get_post();
$activitypub_post = new \Activitypub\Model\Post( $post ); $object = new \Activitypub\Transformer\Post( $post );
$json = \array_merge( array( '@context' => \Activitypub\get_context() ), $activitypub_post->to_array() ); $json = \array_merge( array( '@context' => \Activitypub\get_context() ), $object->to_object()->to_array() );
// filter output // filter output
$json = \apply_filters( 'activitypub_json_post_array', $json ); $json = \apply_filters( 'activitypub_json_post_array', $json );

View file

@ -34,10 +34,7 @@ class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HT
$pre_http_request = new MockAction(); $pre_http_request = new MockAction();
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
$activitypub_post = new \Activitypub\Model\Post( $post ); \Activitypub\Activity_Dispatcher::send_user_activity( get_post( $post ), 'Create' );
\Activitypub\Activity_Dispatcher::send_create_activity( $activitypub_post );
$this->assertNotEmpty( $activitypub_post->get_content() );
$this->assertSame( 2, $pre_http_request->get_call_count() ); $this->assertSame( 2, $pre_http_request->get_call_count() );
$all_args = $pre_http_request->get_args(); $all_args = $pre_http_request->get_args();
@ -77,10 +74,7 @@ class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HT
$pre_http_request = new MockAction(); $pre_http_request = new MockAction();
add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 ); add_filter( 'pre_http_request', array( $pre_http_request, 'filter' ), 10, 3 );
$activitypub_post = new \Activitypub\Model\Post( $post ); \Activitypub\Activity_Dispatcher::send_user_activity( get_post( $post ), 'Create' );
\Activitypub\Activity_Dispatcher::send_create_activity( $activitypub_post );
$this->assertNotEmpty( $activitypub_post->get_content() );
$this->assertSame( 1, $pre_http_request->get_call_count() ); $this->assertSame( 1, $pre_http_request->get_call_count() );
$all_args = $pre_http_request->get_args(); $all_args = $pre_http_request->get_args();

View file

@ -17,10 +17,11 @@ class Test_Activitypub_Activity extends WP_UnitTestCase {
10 10
); );
$activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_post = \Activitypub\Transformer\Post::transform( get_post( $post ) )->to_object();
$activitypub_activity = new \Activitypub\Model\Activity( 'Create' ); $activitypub_activity = new \Activitypub\Activity\Activity();
$activitypub_activity->from_post( $activitypub_post ); $activitypub_activity->set_type( 'Create' );
$activitypub_activity->set_object( $activitypub_post );
$this->assertContains( \Activitypub\get_rest_url_by_path( 'users/1/followers' ), $activitypub_activity->get_to() ); $this->assertContains( \Activitypub\get_rest_url_by_path( 'users/1/followers' ), $activitypub_activity->get_to() );
$this->assertContains( 'https://example.com/alex', $activitypub_activity->get_cc() ); $this->assertContains( 'https://example.com/alex', $activitypub_activity->get_cc() );

View file

@ -10,13 +10,13 @@ class Test_Activitypub_Post extends WP_UnitTestCase {
$permalink = \get_permalink( $post ); $permalink = \get_permalink( $post );
$activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_post = \Activitypub\Transformer\Post::transform( get_post( $post ) )->to_object();
$this->assertEquals( $permalink, $activitypub_post->get_id() ); $this->assertEquals( $permalink, $activitypub_post->get_id() );
\wp_trash_post( $post ); \wp_trash_post( $post );
$activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_post = \Activitypub\Transformer\Post::transform( get_post( $post ) )->to_object();
$this->assertEquals( $permalink, $activitypub_post->get_id() ); $this->assertEquals( $permalink, $activitypub_post->get_id() );
} }

View file

@ -10,9 +10,10 @@ class Test_Activitypub_Signature_Verification extends WP_UnitTestCase {
) )
); );
$remote_actor = \get_author_posts_url( 2 ); $remote_actor = \get_author_posts_url( 2 );
$activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_post = \Activitypub\Transformer\Post::transform( get_post( $post ) )->to_object();
$activitypub_activity = new Activitypub\Model\Activity( 'Create' ); $activitypub_activity = new Activitypub\Activity\Activity( 'Create' );
$activitypub_activity->from_post( $activitypub_post ); $activitypub_activity->set_type( 'Create' );
$activitypub_activity->set_object( $activitypub_post );
$activitypub_activity->add_cc( $remote_actor ); $activitypub_activity->add_cc( $remote_actor );
$activity = $activitypub_activity->to_json(); $activity = $activitypub_activity->to_json();
@ -81,9 +82,10 @@ class Test_Activitypub_Signature_Verification extends WP_UnitTestCase {
); );
$remote_actor = \get_author_posts_url( 2 ); $remote_actor = \get_author_posts_url( 2 );
$remote_actor_inbox = Activitypub\get_rest_url_by_path( '/inbox' ); $remote_actor_inbox = Activitypub\get_rest_url_by_path( '/inbox' );
$activitypub_post = new \Activitypub\Model\Post( $post ); $activitypub_post = \Activitypub\Transformer\Post::transform( \get_post( $post ) )->to_object();
$activitypub_activity = new Activitypub\Model\Activity( 'Create' ); $activitypub_activity = new Activitypub\Activity\Activity();
$activitypub_activity->from_post( $activitypub_post ); $activitypub_activity->set_type( 'Create' );
$activitypub_activity->set_object( $activitypub_post );
$activitypub_activity->add_cc( $remote_actor_inbox ); $activitypub_activity->add_cc( $remote_actor_inbox );
$activity = $activitypub_activity->to_json(); $activity = $activitypub_activity->to_json();