coding standards

This commit is contained in:
Django Doucet 2022-04-15 01:17:00 -06:00
parent 73e6be9782
commit 51643142aa
8 changed files with 187 additions and 198 deletions

View file

@ -50,7 +50,7 @@ class Activity_Dispatcher {
*/ */
public static function send_update_activity( $activitypub_post ) { public static function send_update_activity( $activitypub_post ) {
// save permalink for delete // save permalink for delete
$post_id = \url_to_postid( $activitypub_post->get_id() ); $post_id = \url_to_postid( $activitypub_post->get_id() );
//shouldn't this go in schedule_*_activity? yeah //shouldn't this go in schedule_*_activity? yeah
\update_post_meta( $post_id, '_ap_deleted_slug', $activitypub_post->get_id() ); \update_post_meta( $post_id, '_ap_deleted_slug', $activitypub_post->get_id() );
@ -87,7 +87,7 @@ class Activity_Dispatcher {
foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) { foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) {
$activitypub_activity->set_to( $to ); $activitypub_activity->set_to( $to );
$activity = $activitypub_activity->to_json(); // phpcs:ignore $activity = $activitypub_activity->to_json(); // phpcs:ignore
\Activitypub\safe_remote_post( $inbox, $activity, $user_id ); \Activitypub\safe_remote_post( $inbox, $activity, $user_id );
} }
} }
@ -100,7 +100,7 @@ class Activity_Dispatcher {
public static function send_comment_activity( $activitypub_comment_id ) { public static function send_comment_activity( $activitypub_comment_id ) {
//ONLY FOR LOCAL USERS ? //ONLY FOR LOCAL USERS ?
$activitypub_comment = \get_comment( $activitypub_comment_id ); $activitypub_comment = \get_comment( $activitypub_comment_id );
$user_id = $activitypub_comment->user_id; $user_id = $activitypub_comment->user_id;
$replyto = get_comment_meta( $activitypub_comment->comment_parent, 'comment_author_url', true );// must include in replyto $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 );//might be tagged
@ -121,8 +121,8 @@ class Activity_Dispatcher {
$activity = $activitypub_activity->to_json(); // phpcs:ignore $activity = $activitypub_activity->to_json(); // phpcs:ignore
// Send reply to followers, skip if replying to followers (avoid duplicate replies) // Send reply to followers, skip if replying to followers (avoid duplicate replies)
if( in_array( $cc, $replyto ) || in_array( $cc, $mentions ) ) { if ( in_array( $cc, $replyto ) || in_array( $cc, $mentions ) ) {
continue; continue;
} }
\Activitypub\safe_remote_post( $inbox, $activity, $user_id ); \Activitypub\safe_remote_post( $inbox, $activity, $user_id );
} }
@ -139,24 +139,24 @@ class Activity_Dispatcher {
//original author should NOT recieve a copy of ther own post //original author should NOT recieve a copy of ther own post
$replyto[] = $activitypub_comment->comment_author_url; $replyto[] = $activitypub_comment->comment_author_url;
$activitypub_activity = unserialize( get_comment_meta( $activitypub_comment->comment_ID, 'ap_object', true ) ); $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 //will be forwarded to the parent_comment->author or post_author followers collection
//TODO verify that ... what? //TODO verify that ... what?
$parent_comment = \get_comment( $activitypub_comment->comment_parent ); $parent_comment = \get_comment( $activitypub_comment->comment_parent );
if ( !is_null( $parent_comment ) ) { if ( ! is_null( $parent_comment ) ) {
$user_id = $parent_comment->user_id; $user_id = $parent_comment->user_id;
} else { } else {
$original_post = \get_post( $activitypub_comment->comment_post_ID ); $original_post = \get_post( $activitypub_comment->comment_post_ID );
$user_id = $original_post->post_author; $user_id = $original_post->post_author;
} }
//remove user_id from $activitypub_comment //remove user_id from $activitypub_comment
unset($activitypub_activity['user_id']); unset( $activitypub_activity['user_id'] );
foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) { foreach ( \Activitypub\get_follower_inboxes( $user_id ) as $inbox => $to ) {
//Forward reply to followers, skip sender //Forward reply to followers, skip sender
if( in_array( $to, $replyto ) || ( $replyto == $to ) ) { if ( in_array( $to, $replyto ) || ( $replyto == $to ) ) {
continue; continue;
} }
@ -183,7 +183,7 @@ class Activity_Dispatcher {
} }
$deleted = \wp_date( 'Y-m-d\TH:i:s\Z', \strtotime( $activitypub_comment->comment_date_gmt ) ); $deleted = \wp_date( 'Y-m-d\TH:i:s\Z', \strtotime( $activitypub_comment->comment_date_gmt ) );
$activitypub_comment = new \Activitypub\Model\Comment( $activitypub_comment ); $activitypub_comment = new \Activitypub\Model\Comment( $activitypub_comment );
$activitypub_comment->set_deleted( $deleted ); $activitypub_comment->set_deleted( $deleted );
$activitypub_activity = new \Activitypub\Model\Activity( 'Delete', \Activitypub\Model\Activity::TYPE_FULL ); $activitypub_activity = new \Activitypub\Model\Activity( 'Delete', \Activitypub\Model\Activity::TYPE_FULL );

View file

@ -25,8 +25,8 @@ class Activitypub {
\add_action( 'transition_post_status', array( '\Activitypub\Activitypub', 'schedule_post_activity' ), 10, 3 ); \add_action( 'transition_post_status', array( '\Activitypub\Activitypub', 'schedule_post_activity' ), 10, 3 );
\add_filter( 'preprocess_comment' , array( '\Activitypub\Activitypub', 'preprocess_comment' ) ); \add_filter( 'preprocess_comment', array( '\Activitypub\Activitypub', 'preprocess_comment' ) );
\add_filter( 'comment_post' , array( '\Activitypub\Activitypub', 'postprocess_comment' ), 10, 3 ); \add_filter( 'comment_post', array( '\Activitypub\Activitypub', 'postprocess_comment' ), 10, 3 );
\add_filter( 'wp_update_comment_data', array( '\Activitypub\Activitypub', 'comment_updated_published' ), 20, 3 ); \add_filter( 'wp_update_comment_data', array( '\Activitypub\Activitypub', 'comment_updated_published' ), 20, 3 );
\add_action( 'transition_comment_status', array( '\Activitypub\Activitypub', 'schedule_comment_activity' ), 20, 3 ); \add_action( 'transition_comment_status', array( '\Activitypub\Activitypub', 'schedule_comment_activity' ), 20, 3 );
\add_action( 'edit_comment', array( '\Activitypub\Activitypub', 'edit_comment' ), 20, 2 );//schedule_admin_comment_activity \add_action( 'edit_comment', array( '\Activitypub\Activitypub', 'edit_comment' ), 20, 2 );//schedule_admin_comment_activity
@ -149,7 +149,7 @@ class Activitypub {
*/ */
public static function preprocess_comment( $commentdata ) { public static function preprocess_comment( $commentdata ) {
// only process replies from local actors // only process replies from local actors
if ( !empty( $commentdata['user_id'] ) ) { if ( ! empty( $commentdata['user_id'] ) ) {
$commentdata['comment_type'] = 'activitypub'; $commentdata['comment_type'] = 'activitypub';
// transform webfinger mentions to links and add @mentions to cc // transform webfinger mentions to links and add @mentions to cc
$tagged_content = \Activitypub\transform_tags( $commentdata['comment_content'] ); $tagged_content = \Activitypub\transform_tags( $commentdata['comment_content'] );
@ -167,44 +167,28 @@ class Activitypub {
//Admin users comments bypass transition_comment_status (auto approved) //Admin users comments bypass transition_comment_status (auto approved)
if ( $commentdata['comment_type'] === 'activitypub' ) { if ( $commentdata['comment_type'] === 'activitypub' ) {
if ( if ( ( $comment_approved === 1 ) &&
( $comment_approved === 1 ) &&
! empty( $commentdata['user_id'] ) && ! empty( $commentdata['user_id'] ) &&
( $user = get_userdata( $commentdata['user_id'] ) ) && // get the user data ( $user = get_userdata( $commentdata['user_id'] ) ) && // get the user data
in_array( 'administrator', $user->roles ) // check the roles in_array( 'administrator', $user->roles ) // check the roles
) { ) {
// Only for Admins? // Only for Admins?
$mentions = \get_comment_meta( $comment_id, 'mentions', true ); $mentions = \get_comment_meta( $comment_id, 'mentions', true );
//\ActivityPub\Activity_Dispatcher::send_comment_activity( $comment_id ); // performance > followers collection //\ActivityPub\Activity_Dispatcher::send_comment_activity( $comment_id ); // performance > followers collection
\wp_schedule_single_event( \time(), 'activitypub_send_comment_activity', array( $comment_id ) ); \wp_schedule_single_event( \time(), 'activitypub_send_comment_activity', array( $comment_id ) );
} else { } else {
// TODO check that this is unused // TODO check that this is unused
// TODO comment test as anon / no auth_url, no fetchable status? // TODO comment test as anon / no auth_url, no fetchable status?
// TODO comment test as registered // TODO comment test as registered
// TODO comment test as anyother site settings // TODO comment test as anyother site settings
}
// $replyto = get_comment_meta( $comment_id, 'replyto', true );
//inbox forward prep
// if ( !empty( $ap_object ) ) {
// //if is remote user (has ap_object)
// //error_log( print_r( $ap_object, true ) );
// // TODO verify that deduplication check happens at object create.
// //if to/cc/audience contains local followers collection
// //$local_user = \get_comment_author_url( $comment_id );
// //$is_local_user = \Activitypub\url_to_authorid( $commentdata['comment_author_url'] );
// }
}
} }
} }
/** /**
* edit_comment() * edit_comment()
* *
* Fires immediately after a comment is updated in the database. * Fires immediately after a comment is updated in the database.
* Fires immediately before comment status transition hooks are fired. (useful only for admin) * Fires immediately before comment status transition hooks are fired. (useful only for admin)
*/ */
@ -217,7 +201,7 @@ class Activitypub {
/** /**
* Schedule Activities * Schedule Activities
* *
* transition_comment_status() * transition_comment_status()
* @param int $comment * @param int $comment
*/ */
@ -226,42 +210,40 @@ class Activitypub {
if ( 'approved' === $new_status && 'approved' !== $old_status ) { if ( 'approved' === $new_status && 'approved' !== $old_status ) {
//should only federate replies from local actors //should only federate replies from local actors
//should only federate replies to federated actors //should only federate replies to federated actors
$ap_object = unserialize( \get_comment_meta( $activitypub_comment->comment_ID, 'ap_object', true ) ); $ap_object = unserialize( \get_comment_meta( $activitypub_comment->comment_ID, 'ap_object', true ) );
if ( empty( $ap_object ) ) { if ( empty( $ap_object ) ) {
\wp_schedule_single_event( \time(), 'activitypub_send_comment_activity', array( $activitypub_comment->comment_ID ) ); \wp_schedule_single_event( \time(), 'activitypub_send_comment_activity', array( $activitypub_comment->comment_ID ) );
} else { } else {
$local_user = \get_author_posts_url( $ap_object['user_id'] ); $local_user = \get_author_posts_url( $ap_object['user_id'] );
if ( !is_null( $local_user ) ) { if ( ! is_null( $local_user ) ) {
if ( in_array( $local_user, $ap_object['to'] ) if ( in_array( $local_user, $ap_object['to'] )
|| in_array( $local_user, $ap_object['cc'] ) || in_array( $local_user, $ap_object['cc'] )
|| in_array( $local_user, $ap_object['audience'] ) || in_array( $local_user, $ap_object['audience'] )
|| in_array( $local_user, $ap_object['tag'] ) || in_array( $local_user, $ap_object['tag'] )
) { ) {
//if inReplyTo, object, target and/or tag are (local-wp) objects //if inReplyTo, object, target and/or tag are (local-wp) objects
\wp_schedule_single_event( \time(), 'activitypub_inbox_forward_activity', array( $activitypub_comment->comment_ID ) ); \wp_schedule_single_event( \time(), 'activitypub_inbox_forward_activity', array( $activitypub_comment->comment_ID ) );
} }
} }
} }
} elseif ( 'trash' === $new_status ) { } elseif ( 'trash' === $new_status ) {
\wp_schedule_single_event( \time(), 'activitypub_send_delete_comment_activity', array( $activitypub_comment ) ); \wp_schedule_single_event( \time(), 'activitypub_send_delete_comment_activity', array( $activitypub_comment ) );
} elseif ( $old_status === $new_status ) { } elseif ( $old_status === $new_status ) {
//TODO Test with non-admin user //TODO Test with non-admin user
\wp_schedule_single_event( \time(), 'activitypub_send_update_comment_activity', array( $activitypub_comment->comment_ID ) ); \wp_schedule_single_event( \time(), 'activitypub_send_update_comment_activity', array( $activitypub_comment->comment_ID ) );
} else { } else { }
//error_log( 'schedule_update_comment_activity: else?:' );
}
} }
/** /**
* get_comment_text( $comment ) * get_comment_text( $comment )
* *
* Filters the comment content before it is updated in the database. * Filters the comment content before it is updated in the database.
*/ */
public static function comment_append_edit_datetime( $comment_text, $comment, $args ) { public static function comment_append_edit_datetime( $comment_text, $comment, $args ) {
if ( 'activitypub' === $comment->comment_type ) { if ( 'activitypub' === $comment->comment_type ) {
$updated = \wp_date( 'Y-m-d H:i:s', \strtotime( \get_comment_meta( $comment->comment_ID, 'ap_last_modified', true ) ) ); $updated = \wp_date( 'Y-m-d H:i:s', \strtotime( \get_comment_meta( $comment->comment_ID, 'ap_last_modified', true ) ) );
if( $updated ) { if ( $updated ) {
$append_updated = "<div>(Last edited on <time class='modified' datetime='{$updated}'>$updated</time>)</div>"; $append_updated = "<div>(Last edited on <time class='modified' datetime='{$updated}'>$updated</time>)</div>";
$comment_text .= $append_updated; $comment_text .= $append_updated;
} }

View file

@ -1,7 +1,7 @@
<?php <?php
namespace Activitypub; namespace Activitypub;
define('AS_PUBLIC', 'https://www.w3.org/ns/activitystreams#Public'); define( 'AS_PUBLIC', 'https://www.w3.org/ns/activitystreams#Public' );
/** /**
* Returns the ActivityPub default JSON-context * Returns the ActivityPub default JSON-context
@ -58,7 +58,7 @@ function safe_remote_post( $url, $body, $user_id ) {
$response = \wp_safe_remote_post( $url, $args ); $response = \wp_safe_remote_post( $url, $args );
//\do_action( 'activitypub_safe_remote_post_response', $response, $url, $body, $user_id ); \do_action( 'activitypub_safe_remote_post_response', $response, $url, $body, $user_id );
return $response; return $response;
} }
@ -353,9 +353,8 @@ function url_to_authorid( $url ) {
} }
/** /**
* Verify if in_replyto_url is a local comment, * Verify if in_replyto_url is a local comment,
* Or if it is a previously received remote comment * Or if it is a previously received remote comment
*
* return int comment_id * return int comment_id
*/ */
function url_to_commentid( $in_replyto_url ) { function url_to_commentid( $in_replyto_url ) {
@ -365,11 +364,11 @@ function url_to_commentid( $in_replyto_url ) {
//rewrite for activitypub object id simplification //rewrite for activitypub object id simplification
$url_maybe_id = \wp_parse_url( $in_replyto_url ); $url_maybe_id = \wp_parse_url( $in_replyto_url );
if ( $url_maybe_id['scheme'] . '://' . $url_maybe_id['host'] == site_url() ) { if ( site_url() === $url_maybe_id['scheme'] . '://' . $url_maybe_id['host'] ) {
//is local post or comment //is local post or comment
\parse_str( $url_maybe_id['query'], $reply_query ); \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_int( $reply_query['ap_comment_id'] ) ) {
//is local comment //is local comment
return $reply_query['ap_comment_id']; return $reply_query['ap_comment_id'];
} else { } else {
@ -378,17 +377,17 @@ function url_to_commentid( $in_replyto_url ) {
} }
} else { } else {
//is remote url //is remote url
//verify if in_replyto_url corresponds to a previously received comment //verify if in_replyto_url corresponds to a previously received comment
$comment_args = array( $comment_args = array(
'type' => 'activitypub', 'type' => 'activitypub',
'meta_query' => array( 'meta_query' => array(
array( array(
'key' => 'source_url',//$object['object']['id'] 'key' => 'source_url', //$object['object']['id']
'value' => $in_replyto_url, 'value' => $in_replyto_url,
) ),
) ),
); );
$comments_query = new \WP_Comment_Query; $comments_query = new \WP_Comment_Query();
$comments = $comments_query->query( $comment_args ); $comments = $comments_query->query( $comment_args );
$found_comment_ids = array(); $found_comment_ids = array();
if ( $comments ) { if ( $comments ) {
@ -396,23 +395,22 @@ function url_to_commentid( $in_replyto_url ) {
$found_comment_ids[] = $comment->comment_ID; $found_comment_ids[] = $comment->comment_ID;
} }
return $found_comment_ids[0]; return $found_comment_ids[0];
} }
return null; return null;
} }
} }
/** /**
* Verify if url is a wp_ap_comment, * Verify if url is a wp_ap_comment,
* Or if it is a previously received remote comment * Or if it is a previously received remote comment
*
* return int comment_id * return int comment_id
*/ */
function is_ap_comment() { function is_ap_comment() {
$comment_id = get_query_var( 'ap_comment_id', null ); $comment_id = get_query_var( 'ap_comment_id', null );
if( ! is_null( $comment_id ) ) { if ( ! is_null( $comment_id ) ) {
$comment = \get_comment( $comment_id ); $comment = \get_comment( $comment_id );
// Only return local origin comments // Only return local origin comments
if( $comment->user_id ) { if ( $comment->user_id ) {
return $comment_id; return $comment_id;
} }
} }
@ -420,15 +418,13 @@ function is_ap_comment() {
} }
/** /**
* Verify if url is a /replies endoint, * Verify if url is a /replies endoint,
*
* return int true * return int true
*/ */
function is_ap_replies() { function is_ap_replies() {
global $wp; global $wp;
$replies = get_query_var( 'replies' ); $replies = get_query_var( 'replies' );
//$page = get_query_var( 'collection_page' ); if ( $replies ) {
if( ( $replies ) ) {
return $replies; return $replies;
} }
return null; return null;
@ -436,10 +432,9 @@ function is_ap_replies() {
/** /**
* Get tagged users from received AP object meta * Get tagged users from received AP object meta
* @param string $object_id a comment_id to search * @param string $object_id a comment_id to search
* @param boolean $post defaults to searching a comment_id * @param boolean $post defaults to searching a comment_id
* * @return array of tagged users
* @return array of tagged users
*/ */
function get_recipients( $object_id, $post = null ) { function get_recipients( $object_id, $post = null ) {
$tagged_users_name = null; $tagged_users_name = null;
@ -451,38 +446,38 @@ function get_recipients( $object_id, $post = null ) {
$ap_object = \unserialize( \get_comment_meta( $object_id, 'ap_object', true ) ); $ap_object = \unserialize( \get_comment_meta( $object_id, 'ap_object', true ) );
} }
if ( !empty( $ap_object ) ) { if ( ! empty( $ap_object ) ) {
$tagged_users_name[] = \Activitypub\url_to_webfinger( $ap_object['actor'] ); $tagged_users_name[] = \Activitypub\url_to_webfinger( $ap_object['actor'] );
if ( !empty( $ap_object['object']['tag'] ) ) { if ( ! empty( $ap_object['object']['tag'] ) ) {
$author_post_url = \get_author_posts_url( $ap_object['user_id'] ); $author_post_url = \get_author_posts_url( $ap_object['user_id'] );
foreach ( $ap_object['object']['tag'] as $tag ) { foreach ( $ap_object['object']['tag'] as $tag ) {
if ( $author_post_url == $tag['href'] ) { if ( $author_post_url == $tag['href'] ) {
continue; continue;
} }
if ( in_array( 'Mention', $tag ) ) { if ( in_array( 'Mention', $tag ) ) {
$tagged_users_name[] = $tag['name']; $tagged_users_name[] = $tag['name'];
} }
} }
} }
return implode( ' ', $tagged_users_name ); return implode( ' ', $tagged_users_name );
} }
} }
/** /**
* Add summary to reply * Add summary to reply
*/ */
function get_summary( $comment_id ) { function get_summary( $comment_id ) {
$ap_object = \unserialize( \get_comment_meta( $comment_id, 'ap_object', true ) ); $ap_object = \unserialize( \get_comment_meta( $comment_id, 'ap_object', true ) );
if ( !empty( $ap_object ) ) { if ( ! empty( $ap_object ) ) {
if ( !empty( $ap_object['object']['summary'] ) ) { if ( ! empty( $ap_object['object']['summary'] ) ) {
return \esc_attr( $ap_object['object']['summary'] ); return \esc_attr( $ap_object['object']['summary'] );
} }
} }
} }
/** /**
* parse content for tags to transform * parse content for tags to transform
* @param string $content to search * @param string $content to search
*/ */
function transform_tags( $content ) { function transform_tags( $content ) {
//#tags //#tags
@ -490,7 +485,7 @@ function transform_tags( $content ) {
//@Mentions //@Mentions
$mentions = null; $mentions = null;
$webfinger_tags = \Activitypub\webfinger_extract( $content ); $webfinger_tags = \Activitypub\webfinger_extract( $content );
if ( !empty( $webfinger_tags) ) { if ( ! empty( $webfinger_tags ) ) {
foreach ( $webfinger_tags[0] as $webfinger_tag ) { foreach ( $webfinger_tags[0] as $webfinger_tag ) {
$ap_profile = \Activitypub\Rest\Webfinger::webfinger_lookup( $webfinger_tag ); $ap_profile = \Activitypub\Rest\Webfinger::webfinger_lookup( $webfinger_tag );
if ( ! empty( $ap_profile ) ) { if ( ! empty( $ap_profile ) ) {
@ -499,7 +494,7 @@ function transform_tags( $content ) {
$content = str_replace( $webfinger_tag, $webfinger_link, $content ); $content = str_replace( $webfinger_tag, $webfinger_link, $content );
$mentions[] = $ap_profile; $mentions[] = $ap_profile;
} }
} }
} }
// Return mentions separately to attach to comment/post meta // Return mentions separately to attach to comment/post meta
$content_mentions['mentions'] = $mentions; $content_mentions['mentions'] = $mentions;
@ -522,7 +517,7 @@ function tag_user( $recipient ) {
* @return array of all matched webfinger * @return array of all matched webfinger
*/ */
function webfinger_extract( $string ) { function webfinger_extract( $string ) {
preg_match_all("/@[\._a-zA-Z0-9-]+@[\._a-zA-Z0-9-]+/i", $string, $matches); preg_match_all( '/@[\._a-zA-Z0-9-]+@[\._a-zA-Z0-9-]+/i', $string, $matches );
return $matches; return $matches;
} }
@ -543,16 +538,16 @@ function url_to_webfinger( $user_url ) {
$user_url = \untrailingslashit( $user_url ); $user_url = \untrailingslashit( $user_url );
$user_url_array = explode( '/', $user_url ); $user_url_array = explode( '/', $user_url );
$user_name = end( $user_url_array ); $user_name = end( $user_url_array );
$url_host = parse_url( $user_url , PHP_URL_HOST ); $url_host = parse_url( $user_url, PHP_URL_HOST );
$webfinger = '@' . $user_name . '@' . $url_host; $webfinger = '@' . $user_name . '@' . $url_host;
return $webfinger; return $webfinger;
} }
/** /**
* Transform comment url, replace #fragment with ?query * Transform comment url, replace #fragment with ?query
* *
* AP Object ID must be unique * AP Object ID must be unique
* *
* https://www.w3.org/TR/activitypub/#obj-id * https://www.w3.org/TR/activitypub/#obj-id
* https://github.com/tootsuite/mastodon/issues/13879 * https://github.com/tootsuite/mastodon/issues/13879
*/ */
@ -564,27 +559,27 @@ function normalize_comment_url( $comment ) {
/** /**
* Set ap_comment_id * Set ap_comment_id
* *
* AP Object ID must be unique * AP Object ID must be unique
* *
* https://www.w3.org/TR/activitypub/#obj-id * https://www.w3.org/TR/activitypub/#obj-id
* https://github.com/tootsuite/mastodon/issues/13879 * https://github.com/tootsuite/mastodon/issues/13879
*/ */
function set_ap_comment_id( $comment ) { function set_ap_comment_id( $comment ) {
$ap_comment_id = add_query_arg( $ap_comment_id = add_query_arg(
array( array(
'p' => $comment->comment_post_ID, '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, //should probably rename to ap_comment or something
), ),
trailingslashit( site_url() ) trailingslashit( site_url() )
); );
return $ap_comment_id; return $ap_comment_id;
} }
/* comment_id_to_url( $comment_id ) { /* comment_id_to_url( $comment_id ) {
//get remote from post_id from comment meta //get remote from post_id from comment meta
//get local normalized comment_link //get local normalized comment_link
} }
*/ */
/** /**
* Determine AP audience of incoming object * Determine AP audience of incoming object
@ -598,7 +593,7 @@ function get_audience( $object ) {
if ( in_array( AS_PUBLIC, $object['cc'] ) ) { if ( in_array( AS_PUBLIC, $object['cc'] ) ) {
return 'unlisted';//is unlisted even relevant? return 'unlisted';//is unlisted even relevant?
} }
if ( !in_array( AS_PUBLIC, $object['to'] ) && !in_array( AS_PUBLIC, $object['cc'] ) ) { if ( ! in_array( AS_PUBLIC, $object['to'] ) && ! in_array( AS_PUBLIC, $object['cc'] ) ) {
$author_post_url = get_author_posts_url( $object['user_id'] ); $author_post_url = get_author_posts_url( $object['user_id'] );
if ( in_array( $author_post_url, $object['cc'] ) ) { if ( in_array( $author_post_url, $object['cc'] ) ) {
return 'followers_only'; return 'followers_only';
@ -607,4 +602,4 @@ function get_audience( $object ) {
return 'private'; return 'private';
} }
} }
} }

View file

@ -76,7 +76,7 @@ class Activity {
if ( $this->trash ) { if ( $this->trash ) {
$this->deleted = $timestamp['deleted']; $this->deleted = $timestamp['deleted'];
} }
if ( $this->updated) { if ( $this->updated ) {
$this->updated = $timestamp['updated']; $this->updated = $timestamp['updated'];
} }
} }

View file

@ -58,8 +58,8 @@ class Comment {
), ),
'context' => $this->context, 'context' => $this->context,
//'source' => \get_comment_link( $comment ), //non-conforming, see https://www.w3.org/TR/activitypub/#source-property //'source' => \get_comment_link( $comment ), //non-conforming, see https://www.w3.org/TR/activitypub/#source-property
'url' => \get_comment_link( $comment ),//link for mastodon 'url' => \get_comment_link( $comment ), //link for mastodon
'to' => array( 'https://www.w3.org/ns/activitystreams#Public' ),//audience logic 'to' => array( 'https://www.w3.org/ns/activitystreams#Public' ), //audience logic
'cc' => $this->cc_recipients, 'cc' => $this->cc_recipients,
'tag' => $this->tags, 'tag' => $this->tags,
); );
@ -102,23 +102,23 @@ class Comment {
public function generate_parent_url() { public function generate_parent_url() {
$comment = $this->comment; $comment = $this->comment;
$parent_comment = \get_comment( $comment->comment_parent ); $parent_comment = \get_comment( $comment->comment_parent );
if ( $comment->comment_parent ) { if ( $comment->comment_parent ) {
//is parent remote? //is parent remote?
$inReplyTo = \get_comment_meta( $comment->comment_parent, 'source_url', true ); $inReplyTo = \get_comment_meta( $comment->comment_parent, 'source_url', true );
if ( ! $inReplyTo ) { if ( ! $inReplyTo ) {
$inReplyTo = add_query_arg( $inReplyTo = add_query_arg(
array( array(
'p' => $comment->comment_post_ID, 'p' => $comment->comment_post_ID,
'ap_comment_id' => $comment->comment_parent, 'ap_comment_id' => $comment->comment_parent,
), ),
trailingslashit( site_url() ) trailingslashit( site_url() )
); );
} }
} else { } else {
$inReplyTo = add_query_arg( $inReplyTo = add_query_arg(
array( array(
'p' => $comment->comment_post_ID, 'p' => $comment->comment_post_ID,
), ),
trailingslashit( site_url() ) trailingslashit( site_url() )
); );
} }
@ -127,27 +127,27 @@ class Comment {
public function generate_context() { public function generate_context() {
$comment = $this->comment; $comment = $this->comment;
$inReplyTo = add_query_arg( $inReplyTo = add_query_arg(
array( array(
'p' => $comment->comment_post_ID, 'p' => $comment->comment_post_ID,
), ),
trailingslashit( site_url() ) trailingslashit( site_url() )
); );
return $inReplyTo; return $inReplyTo;
} }
/** /**
* Generate courtesy Content Warning * Generate courtesy Content Warning
* If peer used CW let's just copy it * If peer used CW let's just copy it
* TODO: Move to preprocess_comment / row_actions * TODO: Move to preprocess_comment / row_actions
* Add option for wrapping CW in Details/Summary markup * Add option for wrapping CW in Details/Summary markup
* Figure out some CW syntax: [shortcode-style], {brackets-style}? * Figure out some CW syntax: [shortcode-style], {brackets-style}?
* So it can be inserted into reply textbox, and removed or modified at will * So it can be inserted into reply textbox, and removed or modified at will
*/ */
public function generate_content_warning() { public function generate_content_warning() {
$comment = $this->comment; $comment = $this->comment;
$contentWarning = null; $contentWarning = null;
// TODO Replace auto CW, with Title field or CW shortcode // TODO Replace auto CW, with Title field or CW shortcode
$parent_comment = \get_comment( $comment->comment_parent ); $parent_comment = \get_comment( $comment->comment_parent );
if ( $parent_comment ) { if ( $parent_comment ) {
@ -171,12 +171,12 @@ class Comment {
//TODO Add audience logic get parent audience //TODO Add audience logic get parent audience
//TODO shouldn't mentions go in 'to'? //TODO shouldn't mentions go in 'to'?
$recipients = array( AS_PUBLIC ); $recipients = array( AS_PUBLIC );
$mentions = \get_comment_meta( $this->comment->comment_ID, 'mentions', true ) ; $mentions = \get_comment_meta( $this->comment->comment_ID, 'mentions', true );
if ( !empty( $mentions ) ) { if ( ! empty( $mentions ) ) {
foreach ($mentions as $mention) { foreach ( $mentions as $mention ) {
$recipients[] = $mention['href']; $recipients[] = $mention['href'];
} }
} }
return $recipients; return $recipients;
} }
@ -184,9 +184,9 @@ class Comment {
* Mention user being replied to * Mention user being replied to
*/ */
public function generate_tags() { public function generate_tags() {
$mentions = \get_comment_meta( $this->comment->comment_ID, 'mentions', true ) ; $mentions = \get_comment_meta( $this->comment->comment_ID, 'mentions', true );
if ( !empty( $mentions ) ) { if ( ! empty( $mentions ) ) {
foreach ($mentions as $mention) { foreach ( $mentions as $mention ) {
$mention_tags[] = array( $mention_tags[] = array(
'type' => 'Mention', 'type' => 'Mention',
'href' => $mention['href'], 'href' => $mention['href'],
@ -227,37 +227,43 @@ class Comment {
public function generate_replies() { public function generate_replies() {
$comment = $this->comment; $comment = $this->comment;
$args = array( $args = array(
'post_id' => $comment->comment_post_ID, 'post_id' => $comment->comment_post_ID,
'parent' => $comment->comment_ID, 'parent' => $comment->comment_ID,
'author__in' => $comment->user_id, 'author__in' => $comment->user_id,
'status' => 'approve', 'status' => 'approve',
'hierarchical' => false, 'hierarchical' => false,
); );
$children = \get_comments( $args ); $children = \get_comments( $args );
$replies = null; $replies = null;
if ( $children ) { if ( $children ) {
$items = []; $items = array();
foreach ( $children as $child_comment ){ foreach ( $children as $child_comment ) {
$comment_url = \add_query_arg( $comment_url = \add_query_arg(
array( array(
'p' => $child_comment->comment_post_ID, 'p' => $child_comment->comment_post_ID,
'ap_comment_id' => $child_comment->comment_ID 'ap_comment_id' => $child_comment->comment_ID,
), ),
trailingslashit( site_url() ) trailingslashit( site_url() )
); );
$items[] = $comment_url; $items[] = $comment_url;
} }
$replies = (object) [ $replies = (object) array(
'type' => 'Collection', 'type' => 'Collection',
'id' => \add_query_arg( array( 'replies' => '' ), $this->id ), 'id' => \add_query_arg( array( 'replies' => '' ), $this->id ),
'first' => (object) [ 'first' => (object) array(
'type' => 'CollectionPage', 'type' => 'CollectionPage',
'partOf'=> \add_query_arg( array( 'replies' => '' ), $this->id ), 'partOf' => \add_query_arg( array( 'replies' => '' ), $this->id ),
'next' => \add_query_arg( array( 'replies' => '', 'page' => 1 ), $this->id ), 'next' => \add_query_arg(
'items' => $items array(
], 'replies' => '',
]; 'page' => 1,
),
$this->id
),
'items' => $items,
),
);
} }
return $replies; return $replies;
} }
} }

View file

@ -29,11 +29,11 @@ class Post {
$this->attachments = $this->generate_attachments(); $this->attachments = $this->generate_attachments();
$this->tags = $this->generate_tags(); $this->tags = $this->generate_tags();
$this->object_type = $this->generate_object_type(); $this->object_type = $this->generate_object_type();
$this->replies = $this->generate_replies(); $this->replies = $this->generate_replies();
//$this->updated = $this->generate_updated(); //$this->updated = $this->generate_updated();
$this->slug = \get_permalink( $this->id ); $this->slug = \get_permalink( $this->id );
$this->updated = null; $this->updated = null;
$this->delete = $this->get_deleted(); $this->delete = $this->get_deleted();
} }
public function __call( $method, $params ) { public function __call( $method, $params ) {
@ -90,9 +90,9 @@ class Post {
public function generate_id() { public function generate_id() {
$post = $this->post; $post = $this->post;
$permalink = \add_query_arg( // $permalink = \add_query_arg( //
array( array(
'p' => $post->ID, 'p' => $post->ID,
), ),
trailingslashit( site_url() ) trailingslashit( site_url() )
); );
@ -177,7 +177,7 @@ class Post {
return $tags; return $tags;
} }
public function generate_replies() { public function generate_replies() {
$replies = null; $replies = null;
//\error_log( 'generate_replies: $post' . print_r( $this->post, true ) ); //\error_log( 'generate_replies: $post' . print_r( $this->post, true ) );
@ -185,20 +185,20 @@ class Post {
$args = array( $args = array(
'post_id' => $this->post->ID, // Use post_id, not post_ID 'post_id' => $this->post->ID, // Use post_id, not post_ID
'hierarchical' => false, 'hierarchical' => false,
'status' => 'approve', 'status' => 'approve',
); );
$comments = \get_comments( $args ); $comments = \get_comments( $args );
$items = []; $items = array();
foreach ( $comments as $comment ){ foreach ( $comments as $comment ) {
// include self replies // include self replies
if ( $this->post->post_author === $comment->user_id ) { if ( $this->post->post_author === $comment->user_id ) {
//$comment_url = $comment->comment_ID; //$comment_url = $comment->comment_ID;
$comment_url = \add_query_arg( // $comment_url = \add_query_arg( //
array( array(
'p' => $this->post->ID, 'p' => $this->post->ID,
'ap_comment_id' => $comment->comment_ID 'ap_comment_id' => $comment->comment_ID,
), ),
trailingslashit( site_url() ) trailingslashit( site_url() )
); );
//\error_log( 'generate_replies: $comment' . print_r( $comment, true ) ); //\error_log( 'generate_replies: $comment' . print_r( $comment, true ) );
@ -206,16 +206,22 @@ class Post {
} }
} }
//\error_log( 'generate_replies: $comments' . print_r( $comments, true ) ); //\error_log( 'generate_replies: $comments' . print_r( $comments, true ) );
$replies = (object) [ $replies = (object) array(
'type' => 'Collection', 'type' => 'Collection',
'id' => \add_query_arg( array( 'replies' => '' ), $this->id ), 'id' => \add_query_arg( array( 'replies' => '' ), $this->id ),
'first' => (object) [ 'first' => (object) array(
'type' => 'CollectionPage', 'type' => 'CollectionPage',
'partOf'=> \add_query_arg( array( 'replies' => '' ), $this->id ), 'partOf' => \add_query_arg( array( 'replies' => '' ), $this->id ),
'next' => \add_query_arg( array( 'replies' => '', 'page' => 1 ), $this->id ), 'next' => \add_query_arg(
'items' => $items array(
], 'replies' => '',
]; 'page' => 1,
),
$this->id
),
'items' => $items,
),
);
} }
return $replies; return $replies;
} }
@ -432,7 +438,7 @@ class Post {
$post = $this->post; $post = $this->post;
$deleted = null; $deleted = null;
if ( 'trash' == $post->post_status ) { if ( 'trash' == $post->post_status ) {
$deleted = \date( 'Y-m-d\TH:i:s\Z', \strtotime( $post->post_modified_gmt ) ); $deleted = \date( 'Y-m-d\TH:i:s\Z', \strtotime( $post->post_modified_gmt ) );
\error_log( 'trash: ' . print_r( $deleted, true ) ); \error_log( 'trash: ' . print_r( $deleted, true ) );
} }

View file

@ -414,10 +414,10 @@ class Inbox {
//Determine comment_post_ID and/or comment_parent //Determine comment_post_ID and/or comment_parent
$comment_post_ID = $comment_parent = $comment_parent_ID = 0; $comment_post_ID = $comment_parent = $comment_parent_ID = 0;
if ( isset( $object['object']['inReplyTo'] ) ) { if ( isset( $object['object']['inReplyTo'] ) ) {
$comment_parent_ID = \Activitypub\url_to_commentid( \esc_url_raw( $object['object']['inReplyTo'] ) ); $comment_parent_ID = \Activitypub\url_to_commentid( \esc_url_raw( $object['object']['inReplyTo'] ) );
if ( !is_null( $comment_parent_ID ) ) { if ( ! is_null( $comment_parent_ID ) ) {
//inReplyTo a known local comment //inReplyTo a known local comment
$comment_parent = \get_comment( $comment_parent_ID ); $comment_parent = \get_comment( $comment_parent_ID );
$comment_post_ID = $comment_parent->comment_post_ID; $comment_post_ID = $comment_parent->comment_post_ID;
@ -425,7 +425,7 @@ class Inbox {
//inReplyTo a known post //inReplyTo a known post
$comment_post_ID = \url_to_postid( $object['object']['inReplyTo'] ); $comment_post_ID = \url_to_postid( $object['object']['inReplyTo'] );
} }
} }
//not all implementaions use url //not all implementaions use url
if ( isset( $object['object']['id'] ) ) { if ( isset( $object['object']['id'] ) ) {
@ -435,21 +435,21 @@ class Inbox {
} }
// if no name is set use peer username // if no name is set use peer username
if ( !empty( $meta['name'] ) ) { if ( ! empty( $meta['name'] ) ) {
$name = \esc_attr( $meta['name'] ); $name = \esc_attr( $meta['name'] );
} else { } else {
$name = \esc_attr( $meta['preferredUsername'] ); $name = \esc_attr( $meta['preferredUsername'] );
} }
// if avatar is set // if avatar is set
if ( !empty( $meta['icon']['url'] ) ) { if ( ! empty( $meta['icon']['url'] ) ) {
$avatar_url = \esc_attr( $meta['icon']['url'] ); $avatar_url = \esc_attr( $meta['icon']['url'] );
} }
//Only create WP_Comment for public replies to local posts //Only create WP_Comment for public replies to local posts
if ( ( in_array( AS_PUBLIC, $object['to'] ) if ( ( in_array( AS_PUBLIC, $object['to'] )
|| in_array( AS_PUBLIC, $object['cc'] ) ) || in_array( AS_PUBLIC, $object['cc'] ) )
&& ( !empty( $comment_post_ID ) && ( ! empty( $comment_post_ID )
|| !empty ( $comment_parent ) || ! empty( $comment_parent )
) ) { ) ) {
$commentdata = array( $commentdata = array(
@ -463,7 +463,7 @@ class Inbox {
'comment_meta' => array( 'comment_meta' => array(
'ap_object' => \serialize( $object ), 'ap_object' => \serialize( $object ),
'source_url' => $source_url, 'source_url' => $source_url,
'avatar_url' => $avatar_url, 'avatar_url' => $avatar_url,
'protocol' => 'activitypub', 'protocol' => 'activitypub',
), ),
); );
@ -481,7 +481,7 @@ class Inbox {
// re-add flood control // re-add flood control
//\add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 ); //\add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
} }
} }
/** /**
@ -497,8 +497,8 @@ class Inbox {
//Determine comment_ID //Determine comment_ID
$object_comment_ID = \Activitypub\url_to_commentid( \esc_url_raw( $object['object']['id'] ) ); $object_comment_ID = \Activitypub\url_to_commentid( \esc_url_raw( $object['object']['id'] ) );
if ( !is_null( $object_comment_ID ) ) { if ( ! is_null( $object_comment_ID ) ) {
//found a local comment id //found a local comment id
$commentdata = \get_comment( $object_comment_ID, ARRAY_A ); $commentdata = \get_comment( $object_comment_ID, ARRAY_A );
@ -509,8 +509,8 @@ class Inbox {
$commentdata['comment_meta']['ap_object'] = \serialize( $object ); $commentdata['comment_meta']['ap_object'] = \serialize( $object );
//apply_filters( 'wp_update_comment_data', $data, $comment, $commentarr ); //apply_filters( 'wp_update_comment_data', $data, $comment, $commentarr );
// disable flood control // disable flood control
\remove_action( 'check_comment_flood', 'check_comment_flood_db', 10 ); \remove_action( 'check_comment_flood', 'check_comment_flood_db', 10 );
// do not require email for AP entries // do not require email for AP entries
@ -521,8 +521,8 @@ class Inbox {
\remove_filter( 'pre_option_require_name_email', '__return_false' ); \remove_filter( 'pre_option_require_name_email', '__return_false' );
// re-add flood control // re-add flood control
\add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 ); \add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
} }
} }
/** /**
@ -541,12 +541,12 @@ class Inbox {
} }
//Determine comment_ID //Determine comment_ID
$object_comment_ID = \Activitypub\url_to_commentid( \esc_url_raw( $object['object']['id'] ) ); $object_comment_ID = \Activitypub\url_to_commentid( \esc_url_raw( $object['object']['id'] ) );
if ( !is_null( $object_comment_ID ) ) { if ( ! is_null( $object_comment_ID ) ) {
//found a local comment id //found a local comment id
$commentdata = \get_comment( $object_comment_ID, ARRAY_A ); $commentdata = \get_comment( $object_comment_ID, ARRAY_A );
// disable flood control // disable flood control
\remove_action( 'check_comment_flood', 'check_comment_flood_db', 10 ); \remove_action( 'check_comment_flood', 'check_comment_flood_db', 10 );
// do not require email for AP entries // do not require email for AP entries
@ -558,8 +558,8 @@ class Inbox {
//\remove_filter( 'pre_option_require_name_email', '__return_false' ); //\remove_filter( 'pre_option_require_name_email', '__return_false' );
// re-add flood control // re-add flood control
\add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 ); \add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
} }
} }
public static function extract_recipients( $data ) { public static function extract_recipients( $data ) {

View file

@ -129,9 +129,9 @@ class Webfinger {
*/ */
public static function webfinger_lookup( $webfinger ) { public static function webfinger_lookup( $webfinger ) {
$activity_profile = null; $activity_profile = null;
if ( \substr($webfinger, 0, 1) === '@' ) { if ( \substr( $webfinger, 0, 1 ) === '@' ) {
$webfinger = substr( $webfinger, 1 ); $webfinger = substr( $webfinger, 1 );
} }
$url_host = \explode( '@', $webfinger ); $url_host = \explode( '@', $webfinger );
$webfinger_query = 'https://' . \end( $url_host ) . '/.well-known/webfinger?resource=acct%3A' . \urlencode( $webfinger ); $webfinger_query = 'https://' . \end( $url_host ) . '/.well-known/webfinger?resource=acct%3A' . \urlencode( $webfinger );
@ -140,7 +140,7 @@ class Webfinger {
$ap_link = json_decode( $response['body'] ); $ap_link = json_decode( $response['body'] );
if ( isset( $ap_link->links ) ) { if ( isset( $ap_link->links ) ) {
foreach ( $ap_link->links as $link ) { foreach ( $ap_link->links as $link ) {
if ( !property_exists( $link, 'type' ) ) { if ( ! property_exists( $link, 'type' ) ) {
continue; continue;
} }
if ( isset( $link->type ) && $link->type === 'application/activity+json' ) { if ( isset( $link->type ) && $link->type === 'application/activity+json' ) {
@ -148,9 +148,9 @@ class Webfinger {
$activity_profile['name'] = $webfinger; $activity_profile['name'] = $webfinger;
} }
} }
} }
} }
return $activity_profile; return $activity_profile;
} }
} }