[WIP] Implement WP->Mastodon comment syncing
This commit is contained in:
parent
d133be2e15
commit
87aae44c72
@ -4,13 +4,31 @@ namespace pterotype\comments;
|
||||
require_once plugin_dir_path( __FILE__ ) . '../server/activities/create.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . '../server/activities/update.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . '../server/activities/delete.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . '../server/objects.php';
|
||||
|
||||
function handle_transition_comment_status( $old_status, $new_status, $comment ) {
|
||||
function handle_comment_post( $comment_id, $comment_approved ) {
|
||||
xdebug_break();
|
||||
if ( $comment_approved ) {
|
||||
$comment = \get_comment( $comment_id );
|
||||
handle_transition_comment_status( 'approve', 'nonexistent', $comment );
|
||||
}
|
||||
}
|
||||
|
||||
function handle_edit_comment( $comment_id ) {
|
||||
$comment = \get_comment( $comment_id );
|
||||
if ( $comment->comment_approved ) {
|
||||
handle_transition_comment_status( 'approve', 'approve', $comment );
|
||||
}
|
||||
}
|
||||
|
||||
function handle_transition_comment_status( $new_status, $old_status, $comment ) {
|
||||
xdebug_break();
|
||||
// This creates a new commenter actor if necessary
|
||||
$actor_slug = get_comment_actor_slug( $comment );
|
||||
$actor_outbox = get_rest_url(
|
||||
null, sprintf( 'pterotype/v1/actor/%s/outbox', $actor_slug )
|
||||
);
|
||||
$comment_object = comment_to_object( $comment );
|
||||
$comment_object = comment_to_object( $comment, $actor_slug );
|
||||
$activity = null;
|
||||
if ( $new_status == 'approve' && $old_status != 'approve' ) {
|
||||
// Create
|
||||
@ -24,7 +42,7 @@ function handle_transition_comment_status( $old_status, $new_status, $comment )
|
||||
}
|
||||
if ( $activity && ! is_wp_error( $activity ) ) {
|
||||
$followers = \pterotype\followers\get_followers_collection( $actor_slug );
|
||||
$activity['to'] = get_comment_to( $comment, $followers['id'] );
|
||||
$activity['to'] = get_comment_to( $comment_object, $followers['id'] );
|
||||
$server = rest_get_server();
|
||||
$request = \WP_REST_Request::from_url( $actor_outbox );
|
||||
$request->set_method( 'POST' );
|
||||
@ -43,15 +61,50 @@ function get_comment_actor_slug( $comment ) {
|
||||
}
|
||||
|
||||
function get_comment_user_actor_slug( $user_id ) {
|
||||
|
||||
if ( \user_can( $user_id, 'publish_posts' ) ) {
|
||||
return PTEROTYPE_BLOG_ACTOR_SLUG;
|
||||
} else {
|
||||
$user = \get_userdata( $user_id );
|
||||
return $user->user_nicename;
|
||||
}
|
||||
}
|
||||
|
||||
function get_comment_email_actor_slug( $email_address ) {
|
||||
|
||||
$slug = \pterotype\actors\upsert_commenter_actor( $email_address );
|
||||
return $slug;
|
||||
}
|
||||
|
||||
function comment_to_object( $comment ) {
|
||||
|
||||
function comment_to_object( $comment, $actor_slug ) {
|
||||
$post = \get_post( $comment->comment_post_ID );
|
||||
\setup_postdata( $post );
|
||||
$post_permalink = \get_permalink( $post );
|
||||
$post_object = \pterotype\objects\get_object_by( 'url', $post_permalink );
|
||||
$inReplyTo = $post_object['id'];
|
||||
if ( $comment->comment_parent !== '0' ) {
|
||||
$parent_comment = \get_comment( $comment->comment_parent );
|
||||
$parent_object = \pterotype\objects\get_object_by(
|
||||
'url', \get_comment_link( $parent_comment )
|
||||
);
|
||||
if ( $parent_object ) {
|
||||
$inReplyTo = $parent_object['id'];
|
||||
}
|
||||
}
|
||||
$link = \get_comment_link( $comment );
|
||||
$object = array(
|
||||
'@context' => array( 'https://www.w3.org/ns/activitystreams' ),
|
||||
'type' => 'Note',
|
||||
'content' => $comment->comment_content,
|
||||
'attributedTo' => get_rest_url(
|
||||
null, sprintf( '/pterotype/v1/actor/%s', $actor_slug )
|
||||
),
|
||||
'url' => $link,
|
||||
'inReplyTo' => $inReplyTo,
|
||||
);
|
||||
$existing = \pterotype\objects\get_object_by( 'url', $link );
|
||||
if ( $existing ) {
|
||||
$object['id'] = $existing['id'];
|
||||
}
|
||||
return $object;
|
||||
}
|
||||
|
||||
function get_comment_to( $comment, $followers_id ) {
|
||||
@ -59,7 +112,34 @@ function get_comment_to( $comment, $followers_id ) {
|
||||
'https://www.w3.org/ns/activitystreams#Public',
|
||||
$followers_id,
|
||||
);
|
||||
// TODO traverse comment reply chain to retrieve others to address to
|
||||
$to = array_unique( array_merge( $to, traverse_reply_chain( $comment ) ) );
|
||||
return $to;
|
||||
}
|
||||
|
||||
function traverse_reply_chain( $comment ) {
|
||||
return traverse_reply_chain_helper( $comment, 0, array() );
|
||||
}
|
||||
|
||||
function traverse_reply_chain_helper( $object, $depth, $acc ) {
|
||||
if ( $depth === 50 ) {
|
||||
return $acc;
|
||||
}
|
||||
if ( array_key_exists( 'inReplyTo', $object ) ) {
|
||||
return $acc;
|
||||
}
|
||||
$parent = \pterotype\util\dereference_object( $object['inReplyTo'] );
|
||||
$recipients = array();
|
||||
foreach( array( 'to', 'bto', 'cc', 'bcc', 'audience' ) as $field ) {
|
||||
if ( array_key_exists( $field, $parent ) ) {
|
||||
$new_recipients = $parent[$field];
|
||||
if ( ! is_array( $new_recipients ) ) {
|
||||
$new_recipients = array( $new_recipients );
|
||||
}
|
||||
$recipients = array_unique( array_merge( $recipients, $new_recipients ) );
|
||||
}
|
||||
}
|
||||
return traverse_reply_chain_helper(
|
||||
$parent, $depth + 1, array_unique( array_merge( $acc, $recipients ) )
|
||||
);
|
||||
}
|
||||
?>
|
||||
|
@ -7,6 +7,7 @@ require_once plugin_dir_path( __FILE__ ) . 'server/actors.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . 'schema.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . 'server/webfinger.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . 'client/posts.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . 'client/comments.php';
|
||||
require_once plugin_dir_path( __FILE__ ) . 'server/async.php';
|
||||
|
||||
add_action( 'rest_api_init', function() {
|
||||
@ -36,5 +37,10 @@ add_action( 'parse_request', '\pterotype\webfinger\parse_request', 111 );
|
||||
add_filter( 'query_vars', '\pterotype\webfinger\query_vars' );
|
||||
add_action( 'well_known_webfinger', '\pterotype\webfinger\handle' );
|
||||
add_action( 'transition_post_status', '\pterotype\posts\handle_post_status_change', 10, 3 );
|
||||
add_action(
|
||||
'transition_comment_status', '\pterotype\comments\handle_transition_comment_status', 10, 3
|
||||
);
|
||||
add_action( 'comment_post', '\pterotype\comments\handle_comment_post', 10, 2 );
|
||||
add_action( 'edit_comment', '\pterotype\comments\handle_edit_comment', 10, 1 );
|
||||
add_action( 'template_redirect', '\pterotype\api\handle_non_api_requests' );
|
||||
?>
|
||||
|
@ -180,6 +180,7 @@ function migration_0_0_1() {
|
||||
}
|
||||
|
||||
function migration_1_1_0() {
|
||||
global $wpdb;
|
||||
$wpdb->query(
|
||||
"
|
||||
CREATE TABLE {$wpdb->prefix}pterotype_comments (
|
||||
|
@ -40,12 +40,54 @@ function get_actor_from_row( $row ) {
|
||||
$user = get_user_by( 'slug', $row->slug );
|
||||
return get_user_actor( $user );
|
||||
case 'commenter':
|
||||
return new \WP_Error(
|
||||
'not_implemented', __( 'Commenter actors not yet implemented', 'pterotype' )
|
||||
);
|
||||
return get_commenter_actor( $row->slug );
|
||||
}
|
||||
}
|
||||
|
||||
function get_commenter_actor( $slug ) {
|
||||
$actor_id = get_actor_id( $slug );
|
||||
$email_address = str_replace( '[AT]', '@', $slug );
|
||||
$actor = array(
|
||||
'@context' => array(
|
||||
'https://www.w3.org/ns/activitystreams',
|
||||
'https://w3id.org/security/v1',
|
||||
),
|
||||
'type' => 'Person',
|
||||
'id' => get_rest_url(
|
||||
null, sprintf( '/pterotype/v1/actor/%s', $slug )
|
||||
),
|
||||
'following' => get_rest_url(
|
||||
null, sprintf( '/pterotype/v1/actor/%s/following', $slug )
|
||||
),
|
||||
'followers' => get_rest_url(
|
||||
null, sprintf( '/pterotype/v1/actor/%s/followers', $slug )
|
||||
),
|
||||
'liked' => get_rest_url(
|
||||
null, sprintf( '/pterotype/v1/actor/%s/liked', $slug )
|
||||
),
|
||||
'inbox' => get_rest_url(
|
||||
null, sprintf( '/pterotype/v1/actor/%s/inbox', $slug )
|
||||
),
|
||||
'outbox' => get_rest_url(
|
||||
null, sprintf( '/pterotype/v1/actor/%s/outbox', $slug )
|
||||
),
|
||||
'name' => $email_address,
|
||||
// TODO in the future, make this configurable, both here and in the Webfinger handler
|
||||
'preferredUsername' => $email_address,
|
||||
'publicKey' => array(
|
||||
'id' => get_rest_url(
|
||||
null, sprintf( '/pterotype/v1/actor/%s#publicKey', $slug )
|
||||
),
|
||||
'owner' => get_rest_url(
|
||||
null, sprintf( '/pterotype/v1/actor/%s', $slug )
|
||||
),
|
||||
'publicKeyPem' => \pterotype\pgp\get_public_key( $actor_id ),
|
||||
),
|
||||
);
|
||||
// TODO retrieve commenter name, url, and icon
|
||||
return $actor;
|
||||
}
|
||||
|
||||
function get_blog_actor() {
|
||||
$actor_id = get_actor_id( PTEROTYPE_BLOG_ACTOR_SLUG );
|
||||
$actor = array(
|
||||
@ -175,4 +217,24 @@ function create_actor( $slug, $type ) {
|
||||
}
|
||||
return $res->object;
|
||||
}
|
||||
|
||||
function upsert_commenter_actor( $email_address ) {
|
||||
global $wpdb;
|
||||
$slug = str_replace( '@', '[AT]', $email_address );
|
||||
$existing = $wpdb->get_row( $wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}pterotype_actors WHERE slug = %s",
|
||||
$slug
|
||||
) );
|
||||
if ( $existing !== null ) {
|
||||
return $slug;
|
||||
}
|
||||
create_actor( $slug, 'commenter' );
|
||||
$actor_id = get_actor_id( $slug );
|
||||
$keys_created = \pterotype\pgp\get_public_key( $actor_id );
|
||||
if ( ! $keys_created ) {
|
||||
$keys = \pterotype\pgp\gen_key( $slug );
|
||||
\pterotype\pgp\persist_key( $actor_id, $keys['publickey'], $keys['privatekey'] );
|
||||
}
|
||||
return $slug;
|
||||
}
|
||||
?>
|
||||
|
@ -228,6 +228,15 @@ function get_objects_by( $field, $value ) {
|
||||
);
|
||||
}
|
||||
|
||||
function get_object_by( $field, $value ) {
|
||||
$objects = get_objects_by( $field, $value );
|
||||
if ( count( $objects ) === 0 ) {
|
||||
return null;
|
||||
} else {
|
||||
return $objects[0];
|
||||
}
|
||||
}
|
||||
|
||||
function delete_object( $object ) {
|
||||
global $wpdb;
|
||||
$object = \pterotype\util\dereference_object( $object );
|
||||
|
Loading…
Reference in New Issue
Block a user