Replies Collection, settings, other fixes

This commit is contained in:
Django Doucet 2022-09-27 15:28:45 -06:00
parent 51643142aa
commit 8e1c9ff6bb
11 changed files with 246 additions and 173 deletions

View file

@ -86,6 +86,19 @@ function init() {
}
\add_action( 'plugins_loaded', '\Activitypub\init' );
/**
* Add plugin settings link
*/
function plugin_settings_link( $links ) {
$settings_link[] = \sprintf( '<a href="%1s">%2s</a>',
\menu_page_url( 'activitypub', false ),
\__( 'Settings', 'activitypub' )
);
return \array_merge( $settings_link, $links );
}
\add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), '\Activitypub\plugin_settings_link' );
/**
* Add rewrite rules
*/

View file

@ -15,7 +15,7 @@ class Activity_Dispatcher {
public static function init() {
\add_action( 'activitypub_send_post_activity', array( '\Activitypub\Activity_Dispatcher', 'send_post_activity' ) );
\add_action( 'activitypub_send_update_activity', array( '\Activitypub\Activity_Dispatcher', 'send_update_activity' ) );
\add_action( 'activitypub_send_delete_activity', array( '\Activitypub\Activity_Dispatcher', 'send_delete_activity' ) );
\add_action( 'activitypub_send_delete_activity', array( '\Activitypub\Activity_Dispatcher', 'send_delete_activity', 2 ) );
\add_action( 'activitypub_send_comment_activity', array( '\Activitypub\Activity_Dispatcher', 'send_comment_activity' ) );
\add_action( 'activitypub_send_update_comment_activity', array( '\Activitypub\Activity_Dispatcher', 'send_update_comment_activity' ) );
@ -49,11 +49,6 @@ class Activity_Dispatcher {
* @param \Activitypub\Model\Post $activitypub_post
*/
public static function send_update_activity( $activitypub_post ) {
// save permalink for delete
$post_id = \url_to_postid( $activitypub_post->get_id() );
//shouldn't this go in schedule_*_activity? yeah
\update_post_meta( $post_id, '_ap_deleted_slug', $activitypub_post->get_id() );
// get latest version of post
$user_id = $activitypub_post->get_post_author();
$updated = \wp_date( 'Y-m-d\TH:i:s\Z', \strtotime( $activitypub_post->get_updated() ) );
@ -74,10 +69,13 @@ class Activity_Dispatcher {
*
* @param \Activitypub\Model\Post $activitypub_post
*/
public static function send_delete_activity( $activitypub_post ) {
public static function send_delete_activity( $activitypub_post, $permalink = null ) {
// get latest version of post
$user_id = $activitypub_post->get_post_author();
$deleted = \current_time( 'Y-m-d\TH:i:s\Z', true );
if ( $permalink ) {
$activitypub_post->set_id( $permalink );
}
$activitypub_post->set_deleted( $deleted );
$activitypub_activity = new \Activitypub\Model\Activity( 'Delete', \Activitypub\Model\Activity::TYPE_FULL );
@ -101,27 +99,27 @@ class Activity_Dispatcher {
//ONLY FOR LOCAL USERS ?
$activitypub_comment = \get_comment( $activitypub_comment_id );
$user_id = $activitypub_comment->user_id;
$replyto = get_comment_meta( $activitypub_comment->comment_parent, 'comment_author_url', true );// must include in replyto
$mentions = get_comment_meta( $activitypub_comment_id, 'mentions', true );//might be tagged
$mentions[] = \get_comment_meta( $activitypub_comment_id, 'mentions', true );// mention[href, name]
$activitypub_comment = new \Activitypub\Model\Comment( $activitypub_comment );
$activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_FULL );
$activitypub_activity->from_comment( $activitypub_comment->to_array() );
$mentioned_actors = array();
foreach ( \Activitypub\get_mentioned_inboxes( $mentions ) as $inbox => $to ) {
$activitypub_activity->set_to( $to );//all users at shared inbox
$activity = $activitypub_activity->to_json(); // phpcs:ignore
\Activitypub\safe_remote_post( $inbox, $activity, $user_id );
$mentioned_actors[] = $to;
}
//will this reset the activities?
foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $cc ) {
$activitypub_activity->set_cc( $cc );//set_cc
$activity = $activitypub_activity->to_json(); // phpcs:ignore
// Send reply to followers, skip if replying to followers (avoid duplicate replies)
if ( in_array( $cc, $replyto ) || in_array( $cc, $mentions ) ) {
// Send reply to followers, skip if mentioned followers (avoid duplicate replies)
if ( in_array( $cc, $mentioned_actors ) ) {
continue;
}
\Activitypub\safe_remote_post( $inbox, $activity, $user_id );
@ -136,12 +134,11 @@ class Activity_Dispatcher {
public static function inbox_forward_activity( $activitypub_comment_id ) {
$activitypub_comment = \get_comment( $activitypub_comment_id );
//original author should NOT recieve a copy of ther own post
//original author should NOT recieve a copy of their own post
$replyto[] = $activitypub_comment->comment_author_url;
$activitypub_activity = unserialize( get_comment_meta( $activitypub_comment->comment_ID, 'ap_object', true ) );
//will be forwarded to the parent_comment->author or post_author followers collection
//TODO verify that ... what?
$parent_comment = \get_comment( $activitypub_comment->comment_parent );
if ( ! is_null( $parent_comment ) ) {
$user_id = $parent_comment->user_id;
@ -150,18 +147,16 @@ class Activity_Dispatcher {
$user_id = $original_post->post_author;
}
//remove user_id from $activitypub_comment
unset( $activitypub_activity['user_id'] );
foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) {
unset( $activitypub_activity['user_id'] ); // remove user_id from $activitypub_comment
foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $cc ) {
//Forward reply to followers, skip sender
if ( in_array( $to, $replyto ) || ( $replyto == $to ) ) {
if ( in_array( $cc, $replyto ) ) {
continue;
}
$activitypub_activity['object']['to'] = $to;
$activitypub_activity['to'] = $to;
$activitypub_activity['object']['cc'] = $cc;
$activitypub_activity['cc'] = $cc;
$activity = \wp_json_encode( $activitypub_activity, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_QUOT );
\Activitypub\forward_remote_post( $inbox, $activity, $user_id );

View file

@ -42,7 +42,7 @@ class Activitypub {
* @return string The new path to the JSON template.
*/
public static function render_json_template( $template ) {
if ( ! \is_author() && ! \is_singular() && ! \is_home() && ! \Activitypub\is_ap_comment() ) {
if ( ! \is_author() && ! \is_singular() && ! \is_home() && ! \Activitypub\is_ap_comment() && ! \Activitypub\is_ap_replies() ) {
return $template;
}
@ -169,12 +169,11 @@ class Activitypub {
if ( $commentdata['comment_type'] === 'activitypub' ) {
if ( ( $comment_approved === 1 ) &&
! empty( $commentdata['user_id'] ) &&
( $user = get_userdata( $commentdata['user_id'] ) ) && // get the user data
in_array( 'administrator', $user->roles ) // check the roles
( $user = \get_userdata( $commentdata['user_id'] ) ) && // get the user data
\in_array( 'administrator', $user->roles ) // check the roles
) {
// Only for Admins?
// Only for Admins
$mentions = \get_comment_meta( $comment_id, 'mentions', true );
//\ActivityPub\Activity_Dispatcher::send_comment_activity( $comment_id ); // performance > followers collection
\wp_schedule_single_event( \time(), 'activitypub_send_comment_activity', array( $comment_id ) );
} else {
@ -193,7 +192,6 @@ class Activitypub {
* Fires immediately before comment status transition hooks are fired. (useful only for admin)
*/
public static function edit_comment( $comment_ID, $data ) {
// advantage of ap_published is it would be set once, (does preprocess fire on edit?)
if ( ! is_null( $data['user_id'] ) ) {
\wp_schedule_single_event( \time(), 'activitypub_send_update_comment_activity', array( $comment_ID ) );
}

View file

@ -164,44 +164,31 @@ class Admin {
// Public Reply
$reply_button = '<button type="button" data-comment-id="%d" data-post-id="%d" data-action="%s" class="%s button-link" aria-expanded="false" aria-label="%s" data-recipients="%s" data-summary="%s">%s</button>';
$actions['reply'] = sprintf(
$reply_button,
$comment->comment_ID,
$comment->comment_post_ID,
'replyto',
'vim-r comment-inline',
$reply_button,
$comment->comment_ID,
$comment->comment_post_ID,
'replyto',
'vim-r comment-inline',
esc_attr__( 'Reply to this comment' ),
$recipients,
$summary,
__( 'Reply', 'activitypub' )
__( 'Reply', 'activitypub' )
);
// Private
// $actions['private_reply'] = sprintf(
// $format,
// $comment->comment_ID,
// $comment->comment_post_ID,
// 'private_replyto',
// 'vim-r comment-inline',
// esc_attr__( 'Reply in private to this comment' ),
// $recipients,
// $summary,
// __( 'Private reply', 'activitypub' )
// );
return $actions;
}
public static function scripts_reply_comments( $hook ) {
if ('edit-comments.php' !== $hook) {
if ( 'edit-comments.php' !== $hook ) {
return;
}
wp_enqueue_script( 'activitypub_client',
plugin_dir_url(__FILE__) . '/activitypub.js',
array('jquery'),
filemtime( plugin_dir_path(__FILE__) . '/activitypub.js' ),
true
wp_enqueue_script(
'activitypub_client',
plugin_dir_url( __FILE__ ) . '/activitypub.js',
array( 'jquery' ),
filemtime( plugin_dir_path( __FILE__ ) . '/activitypub.js' ),
true
);
}
}

View file

@ -251,6 +251,12 @@ function get_follower_inboxes( $user_id ) {
return $inboxes;
}
/**
*
* @param $mentions array of mentioned actors, each mention is an array of actor URI (href), and webfinger (name)
*
* @return array of (shared) inboxes
*/
function get_mentioned_inboxes( $mentions ) {
$inboxes = array();
@ -259,7 +265,7 @@ function get_mentioned_inboxes( $mentions ) {
if ( ! $inbox || \is_wp_error( $inbox ) ) {
continue;
}
// init array if empty
if ( ! isset( $inboxes[ $inbox ] ) ) {
$inboxes[ $inbox ] = array();
}
@ -355,7 +361,10 @@ function url_to_authorid( $url ) {
/**
* Verify if in_replyto_url is a local comment,
* Or if it is a previously received remote comment
* return int comment_id
* (For threading comments locally)
*
* @param string activitypub object id URI
* @return int comment_id
*/
function url_to_commentid( $in_replyto_url ) {
if ( empty( $in_replyto_url ) ) {
@ -364,16 +373,12 @@ function url_to_commentid( $in_replyto_url ) {
//rewrite for activitypub object id simplification
$url_maybe_id = \wp_parse_url( $in_replyto_url );
if ( site_url() === $url_maybe_id['scheme'] . '://' . $url_maybe_id['host'] ) {
if ( site_url() === $url_maybe_id['scheme'] . '://' . $url_maybe_id['host'] && !empty( $url_maybe_id['query'] )) {
//is local post or comment
\parse_str( $url_maybe_id['query'], $reply_query );
if ( isset( $reply_query['ap_comment_id'] ) && is_int( $reply_query['ap_comment_id'] ) ) {
if ( isset( $reply_query['ap_comment_id'] ) ) {
//is local comment
return $reply_query['ap_comment_id'];
} else {
//not a comment
return null;
}
} else {
//is remote url
@ -396,14 +401,14 @@ function url_to_commentid( $in_replyto_url ) {
}
return $found_comment_ids[0];
}
return null;
}
return null;
}
/**
* Verify if url is a wp_ap_comment,
* Or if it is a previously received remote comment
* return int comment_id
* @return int comment_id
*/
function is_ap_comment() {
$comment_id = get_query_var( 'ap_comment_id', null );
@ -418,11 +423,10 @@ function is_ap_comment() {
}
/**
* Verify if url is a /replies endoint,
* return int true
* Verify if url has a replies query,
* @return bool
*/
function is_ap_replies() {
global $wp;
$replies = get_query_var( 'replies' );
if ( $replies ) {
return $replies;
@ -476,8 +480,10 @@ function get_summary( $comment_id ) {
}
/**
* parse content for tags to transform
* Parse content for tags to transform
*
* @param string $content to search
* @return array content, mentions (for storage in post_meta)
*/
function transform_tags( $content ) {
//#tags
@ -544,21 +550,8 @@ function url_to_webfinger( $user_url ) {
}
/**
* Transform comment url, replace #fragment with ?query
*
* AP Object ID must be unique
*
* https://www.w3.org/TR/activitypub/#obj-id
* https://github.com/tootsuite/mastodon/issues/13879
*/
function normalize_comment_url( $comment ) {
$comment_id = explode( '#comment-', \get_comment_link( $comment ) );
$comment_id = $comment_id[0] . '?ap_comment_id=' . $comment_id[1];
return $comment_id;
}
/**
* Set ap_comment_id
* @param $comment or $comment_id
* @return ActivityPub URI of comment
*
* AP Object ID must be unique
*
@ -566,20 +559,16 @@ function normalize_comment_url( $comment ) {
* https://github.com/tootsuite/mastodon/issues/13879
*/
function set_ap_comment_id( $comment ) {
$comment = \get_comment( $comment );
$ap_comment_id = add_query_arg(
array(
'p' => $comment->comment_post_ID,
'ap_comment_id' => $comment->comment_ID, //should probably rename to ap_comment or something
'ap_comment_id' => $comment->comment_ID,
),
trailingslashit( site_url() )
);
return $ap_comment_id;
}
/* comment_id_to_url( $comment_id ) {
//get remote from post_id from comment meta
//get local normalized comment_link
}
*/
/**
* Determine AP audience of incoming object
@ -591,7 +580,7 @@ function get_audience( $object ) {
return 'public';
}
if ( in_array( AS_PUBLIC, $object['cc'] ) ) {
return 'unlisted';//is unlisted even relevant?
return 'unlisted';
}
if ( ! in_array( AS_PUBLIC, $object['to'] ) && ! in_array( AS_PUBLIC, $object['cc'] ) ) {
$author_post_url = get_author_posts_url( $object['user_id'] );

View file

@ -23,7 +23,7 @@ class Comment {
$this->contentWarning = $this->generate_content_warning();
$this->permalink = $this->generate_permalink();
$this->context = $this->generate_context();
$this->cc_recipients = $this->generate_recipients();
$this->to_recipients = $this->generate_mention_recipients();
$this->tags = $this->generate_tags();
$this->update = $this->generate_update();
$this->deleted = $this->generate_trash();
@ -59,9 +59,10 @@ class Comment {
'context' => $this->context,
//'source' => \get_comment_link( $comment ), //non-conforming, see https://www.w3.org/TR/activitypub/#source-property
'url' => \get_comment_link( $comment ), //link for mastodon
'to' => array( 'https://www.w3.org/ns/activitystreams#Public' ), //audience logic
'cc' => $this->cc_recipients,
'to' => $this->to_recipients,
'cc' => array( 'https://www.w3.org/ns/activitystreams#Public' ),
'tag' => $this->tags,
'replies' => $this->replies,
);
if ( $this->replies ) {
$array['replies'] = $this->replies;
@ -85,7 +86,7 @@ class Comment {
}
public function generate_comment_id() {
return \Activitypub\set_ap_comment_id( $this->comment );
return \Activitypub\set_ap_comment_id( $this->comment->comment_ID );
}
public function generate_permalink() {
@ -96,7 +97,7 @@ class Comment {
}
/**
* What is status is being replied to
* What is status being replied to
* Comment ID or Post ID
*/
public function generate_parent_url() {
@ -114,31 +115,43 @@ class Comment {
trailingslashit( site_url() )
);
}
} else {
$inReplyTo = add_query_arg(
array(
'p' => $comment->comment_post_ID,
),
trailingslashit( site_url() )
);
} else { //parent is_post
// Backwards compatibility
$pretty_permalink = \get_post_meta( $comment->comment_post_ID, '_activitypub_permalink_compat', true ); // TODO finalize meta
if ( $pretty_permalink ) {
$inReplyTo = $pretty_permalink;
} else {
$inReplyTo = add_query_arg(
array(
'p' => $comment->comment_post_ID,
),
trailingslashit( site_url() )
);
}
}
return $inReplyTo;
}
public function generate_context() {
$comment = $this->comment;
$inReplyTo = add_query_arg(
array(
'p' => $comment->comment_post_ID,
),
trailingslashit( site_url() )
);
return $inReplyTo;
// support pretty_permalinks
$pretty_permalink = \get_post_meta( $comment->comment_post_ID, '_activitypub_permalink_compat', true );
if ( $pretty_permalink ) {
$context = $pretty_permalink;
} else {
$context = add_query_arg(
array(
'p' => $comment->comment_post_ID,
),
trailingslashit( site_url() )
);
}
return $context;
}
/**
* Generate courtesy Content Warning
* If peer used CW let's just copy it
* If parent status used CW let's just copy it
* TODO: Move to preprocess_comment / row_actions
* Add option for wrapping CW in Details/Summary markup
* Figure out some CW syntax: [shortcode-style], {brackets-style}?
@ -148,7 +161,7 @@ class Comment {
$comment = $this->comment;
$contentWarning = null;
// TODO Replace auto CW, with Title field or CW shortcode
// Temporarily generate Summary from parent
$parent_comment = \get_comment( $comment->comment_parent );
if ( $parent_comment ) {
//get (received) comment
@ -157,9 +170,10 @@ class Comment {
$contentWarning = $ap_object['object']['summary'];
}
}
// TODO Replace auto generate with Summary shortcode
/*summary = \get_comment_meta( $this->comment->comment_ID, 'summary', true ) ;
if ( !empty( $summary ) ) {
$contentWarning = \Activitypub\add_summary( $summary ); //TODO
$contentWarning = \Activitypub\add_summary( $summary );
} */
return $contentWarning;
}
@ -167,9 +181,7 @@ class Comment {
/**
* Who is being replied to
*/
public function generate_recipients() {
//TODO Add audience logic get parent audience
//TODO shouldn't mentions go in 'to'?
public function generate_mention_recipients() {
$recipients = array( AS_PUBLIC );
$mentions = \get_comment_meta( $this->comment->comment_ID, 'mentions', true );
if ( ! empty( $mentions ) ) {
@ -226,40 +238,41 @@ class Comment {
*/
public function generate_replies() {
$comment = $this->comment;
$replies = [];
$args = array(
'post_id' => $comment->comment_post_ID,
'parent' => $comment->comment_ID,
'author__in' => $comment->user_id,
'status' => 'approve',
'hierarchical' => false,
);
$children = \get_comments( $args );
$replies = null;
if ( $children ) {
$comments_list = \get_comments( $args );
if ( $comments_list ) {
$items = array();
foreach ( $children as $child_comment ) {
$comment_url = \add_query_arg(
array(
'p' => $child_comment->comment_post_ID,
'ap_comment_id' => $child_comment->comment_ID,
),
trailingslashit( site_url() )
);
$items[] = $comment_url;
foreach ( $comments_list as $comment ) {
// remote replies
$source_url = \get_comment_meta( $comment->comment_ID, 'source_url', true );
if ( ! empty( $source_url ) ){
$items[] = $source_url;
} else {
// local replies
$comment_url = \add_query_arg( //
array(
'p' => $comment->comment_post_ID,
'ap_comment_id' => $comment->comment_ID,
),
trailingslashit( site_url() )
);
$items[] = $comment_url;
}
}
$replies = (object) array(
'type' => 'Collection',
'id' => \add_query_arg( array( 'replies' => '' ), $this->id ),
'first' => (object) array(
'type' => 'CollectionPage',
'partOf' => \add_query_arg( array( 'replies' => '' ), $this->id ),
'next' => \add_query_arg(
array(
'replies' => '',
'page' => 1,
),
$this->id
),
'items' => $items,
),
);

View file

@ -30,9 +30,7 @@ class Post {
$this->tags = $this->generate_tags();
$this->object_type = $this->generate_object_type();
$this->replies = $this->generate_replies();
//$this->updated = $this->generate_updated();
$this->slug = \get_permalink( $this->id );
$this->updated = null;
$this->updated = $this->generate_updated();
$this->delete = $this->get_deleted();
}
@ -73,9 +71,10 @@ class Post {
}
if ( $this->deleted ) {
$array['deleted'] = \date( 'Y-m-d\TH:i:s\Z', \strtotime( $post->post_modified_gmt ) );
// TODO if using slugs instead of ids _ap_deleted_slug
//$deleted_post_slug = \get_post_meta( $post->ID, '_ap_deleted_slug', true );
//$array['id'] = $deleted_post_slug;
$deleted_post_slug = \get_post_meta( $post->ID, '_activitypub_permalink_compat', true );
if ( $deleted_post_slug ) {
$array['id'] = $deleted_post_slug;
}
}
if ( $this->updated ) {
$array['updated'] = \date( 'Y-m-d\TH:i:s\Z', \strtotime( $post->post_modified_gmt ) );
@ -89,15 +88,19 @@ class Post {
public function generate_id() {
$post = $this->post;
$permalink = \add_query_arg( //
array(
'p' => $post->ID,
),
trailingslashit( site_url() )
);
$pretty_permalink = \get_post_meta( $post->ID, '_activitypub_permalink_compat', true );
// replace 'trashed' for delete activity
return \str_replace( '__trashed', '', $permalink );
if( ! empty( $pretty_permalink ) ) {
$object_id = $pretty_permalink;
} else {
$object_id = \add_query_arg( //
array(
'p' => $post->ID,
),
trailingslashit( site_url() )
);
}
return $object_id;
}
public function generate_attachments() {
@ -180,10 +183,9 @@ class Post {
public function generate_replies() {
$replies = null;
//\error_log( 'generate_replies: $post' . print_r( $this->post, true ) );
if ( $this->post->comment_count > 0 ) {
$args = array(
'post_id' => $this->post->ID, // Use post_id, not post_ID
'post_id' => $this->post->ID,
'hierarchical' => false,
'status' => 'approve',
);
@ -193,7 +195,6 @@ class Post {
foreach ( $comments as $comment ) {
// include self replies
if ( $this->post->post_author === $comment->user_id ) {
//$comment_url = $comment->comment_ID;
$comment_url = \add_query_arg( //
array(
'p' => $this->post->ID,
@ -201,24 +202,23 @@ class Post {
),
trailingslashit( site_url() )
);
//\error_log( 'generate_replies: $comment' . print_r( $comment, true ) );
$items[] = $comment_url;
} else {
$ap_object = \unserialize(\get_comment_meta( $comment->comment_ID, 'ap_object', true ));
$comment_url = \get_comment_meta( $comment->comment_ID, 'source_url', true );
if ( ! empty( $comment_url ) ){
$items[] = \get_comment_meta( $comment->comment_ID, 'source_url', true );
}
}
}
//\error_log( 'generate_replies: $comments' . print_r( $comments, true ) );
$replies = (object) array(
'type' => 'Collection',
'id' => \add_query_arg( array( 'replies' => '' ), $this->id ),
'first' => (object) array(
'type' => 'CollectionPage',
'partOf' => \add_query_arg( array( 'replies' => '' ), $this->id ),
'next' => \add_query_arg(
array(
'replies' => '',
'page' => 1,
),
$this->id
),
'items' => $items,
),
);

View file

@ -427,13 +427,6 @@ class Inbox {
}
}
//not all implementaions use url
if ( isset( $object['object']['id'] ) ) {
$source_url = \esc_url_raw( $object['object']['id'] );
} else {
$source_url = \esc_url_raw( $object['object']['url'] );
}
// if no name is set use peer username
if ( ! empty( $meta['name'] ) ) {
$name = \esc_attr( $meta['name'] );
@ -446,10 +439,10 @@ class Inbox {
}
//Only create WP_Comment for public replies to local posts
if ( ( in_array( AS_PUBLIC, $object['to'] )
|| in_array( AS_PUBLIC, $object['cc'] ) )
if ( ( 'public' === $audience )
|| ( 'unlisted' === $audience )
&& ( ! empty( $comment_post_ID )
|| ! empty( $comment_parent )
|| ! empty( $comment_parent_ID )
) ) {
$commentdata = array(
@ -462,7 +455,7 @@ class Inbox {
'comment_parent' => $comment_parent_ID,
'comment_meta' => array(
'ap_object' => \serialize( $object ),
'source_url' => $source_url,
'source_url' => \esc_url_raw( $object['object']['id'] ),
'avatar_url' => $avatar_url,
'protocol' => 'activitypub',
),

View file

@ -126,6 +126,7 @@ class Webfinger {
* WebFinger Lookup to find user uri
*
* @param string $resource the WebFinger resource
* @return array ['href', 'name']. ex: href=https://domain.tld/user/webfinger, name=webfinger@domain.tld
*/
public static function webfinger_lookup( $webfinger ) {
$activity_profile = null;

View file

@ -1,5 +1,5 @@
<?php
$comment = \get_comment( get_query_var('ap_comment_id') );
$comment = \get_comment( \get_query_var( 'ap_comment_id' ) );
$activitypub_comment = new \Activitypub\Model\Comment( $comment );
$json = \array_merge( array( '@context' => \Activitypub\get_context() ), $activitypub_comment->to_array() );

View file

@ -0,0 +1,84 @@
<?php
$post = \get_post();
$page = \get_query_var( 'page' );
$args = array(
'status' => 'approve',
'number' => '10',
'offset' => $page,
'type' => 'activitypub',
'post_id' => $post->ID,
'order' => 'ASC',
);
$comments = get_comments( $args );
$replies_request = \add_query_arg( $_SERVER['QUERY_STRING'], '', $post->guid );
$collection_id = \remove_query_arg(['page', 'ap_comment_id'], $replies_request );
$json = new \stdClass();
$json->{'@context'} = 'https://www.w3.org/ns/activitystreams';
$json->id = $collection_id;
$collectionPage = new \stdClass();
$collectionPage->type = 'CollectionPage';
$collectionPage->partOf = $collection_id;
$collectionPage->totalItems = \count( $comments ); // phpcs:ignore
if ( $page && ( ( \ceil ( $collectionPage->totalItems / 10 ) ) > $page ) ) { // phpcs:ignore
$collectionPage->first = \add_query_arg( 'page', 1, $collectionPage->partOf ); // phpcs:ignore TODO
$collectionPage->next = \add_query_arg( 'page', $page + 1, $collectionPage->partOf ); // phpcs:ignore
$collectionPage->last = \add_query_arg( 'page', \ceil ( $collectionPage->totalItems / 10 ), $collectionPage->partOf ); // phpcs:ignore
}
foreach ( $comments as $comment ) {
$remote_url = \get_comment_meta( $comment->comment_ID, 'source_url', true );
if ( $remote_url ) { //
$collectionPage->items[] = $remote_url;
} else {
$activitypub_comment = new \Activitypub\Model\Comment( $comment );
$activitypub_activity = new \Activitypub\Model\Activity( 'Create', \Activitypub\Model\Activity::TYPE_NONE );
$activitypub_activity->from_post( $activitypub_comment->to_array() );
$collectionPage->items[] = $activitypub_activity->to_array(); // phpcs:ignore
}
}
if ( ! \get_query_var( 'collection_page' ) ) {
$json->type = 'Collection';
//if +10, embed first
$json->first = $collectionPage;
} else {
$json = $collectionPage;
}
// filter output
$json = \apply_filters( 'activitypub_json_replies_array', $json );
/*
* Action triggerd prior to the ActivityPub profile being created and sent to the client
*/
\do_action( 'activitypub_json_replies_pre' );
$options = 0;
// JSON_PRETTY_PRINT added in PHP 5.4
if ( \get_query_var( 'pretty' ) ) {
$options |= \JSON_PRETTY_PRINT; // phpcs:ignore
}
$options |= \JSON_HEX_TAG | \JSON_HEX_AMP | \JSON_HEX_QUOT;
/*
* Options to be passed to json_encode()
*
* @param int $options The current options flags
*/
$options = \apply_filters( 'activitypub_json_replies_options', $options );
\header( 'Content-Type: application/activity+json' );
echo \wp_json_encode( $json, $options );
/*
* Action triggerd after the ActivityPub profile has been created and sent to the client
*/
\do_action( 'activitypub_json_replies_comment' );