[WIP] Handle activity creation on post update/publish/trash

This commit is contained in:
Jeremy Dormitzer 2018-10-07 19:12:45 -04:00
parent 9c371b4720
commit 26dbfe6d2c
9 changed files with 121 additions and 26 deletions

63
includes/client/posts.php Normal file
View File

@ -0,0 +1,63 @@
<?php
namespace posts;
require_once plugin_dir_path( __FILE__ ) . '../server/activities/create.php';
function handle_post_status_change( $new_status, $old_status, $post ) {
// TODO find a way to get the id of an existing object for the post, if it exists
$actor_slug = PTEROTYPE_BLOG_ACTOR_SLUG;
$actor_outbox = get_rest_url(
null, sprintf( 'pterotype/v1/actor/%s/outbox', $actor_slug )
);
$post_object = post_to_object( $post );
$activity = null;
if ( $new_status == 'publish' && $old_status != 'publish' ) {
// Create
$activity = \activities\create\make_create( $actor_slug, $post_object );
} else if ( $new_status == 'publish' && $old_status == 'publish' ) {
// Update
$activity = \activities\update\make_update( $actor_slug, $post_object );
} else if ( $new_status != 'publish' && $old_status == 'publish' ) {
// Delete
// TODO delete isn't working
$activity = \activities\delete\make_delete( $actor_slug, $post_object );
}
if ( $activity && ! is_wp_error( $activity ) ) {
$server = rest_get_server();
$request = \WP_REST_Request::from_url( $actor_outbox );
$request->set_method('POST');
$request->set_body( wp_json_encode( $activity ) );
$request->add_header( 'Content-Type', 'application/ld+json' );
$server->dispatch( $request );
}
}
/**
Return an object of type Article
*/
function post_to_object( $post ) {
$object = array(
'@context' => array( 'https://www.w3.org/ns/activitystreams' ),
'type' => 'Article',
'name' => $post->post_title,
'content' => $post->post_content,
'attributedTo' => get_rest_url(
null, sprintf( '/pterotype/v1/actor/%s', PTEROTYPE_BLOG_ACTOR_SLUG )
),
'url' => get_permalink( $post ),
'summary' => $post->post_excerpt,
);
$existing = get_existing_object( $post );
if ( $existing ) {
$object['id'] = $existing->activitypub_id;
}
return $object;
}
function get_existing_object( $post ) {
global $wpdb;
return $wpdb->get_row( $wpdb->prepare(
'SELECT * FROM pterotype_objects WHERE object->"$.url" = %s', get_permalink( $post )
) );
}
?>

View File

@ -5,6 +5,7 @@ require_once plugin_dir_path( __FILE__ ) . 'server/api.php';
require_once plugin_dir_path( __FILE__ ) . 'server/actors.php';
require_once plugin_dir_path( __FILE__ ) . 'migrations.php';
require_once plugin_dir_path( __FILE__ ) . 'server/webfinger.php';
require_once plugin_dir_path( __FILE__ ) . 'client/posts.php';
add_action( 'rest_api_init', function() {
\api\register_routes();
@ -27,4 +28,5 @@ add_action( 'generate_rewrite_rules', '\webfinger\generate_rewrite_rules', 111 )
add_action( 'parse_request', '\webfinger\parse_request', 111 );
add_filter( 'query_vars', '\webfinger\query_vars' );
add_action( 'well_known_webfinger', '\webfinger\handle' );
add_action( 'transition_post_status', '\posts\handle_post_status_change', 10, 3 );
?>

View File

@ -20,7 +20,6 @@ function persist_key( $actor_id, $public_key, $private_key ) {
}
function sign_data( $data, $actor_id ) {
xdebug_break();
$secret_key = get_private_key( $actor_id );
$sig = null;
openssl_sign( $data, $sig, $secret_key );
@ -30,7 +29,7 @@ function sign_data( $data, $actor_id ) {
__( 'Unable to sign data', 'pterotype' )
);
}
return $sig;
return base64_encode( $sig );
}
function get_public_key( $actor_id ) {

View File

@ -2,6 +2,7 @@
namespace activities\create;
require_once plugin_dir_path( __FILE__ ) . '../objects.php';
require_once plugin_dir_path( __FILE__ ) . '../actors.php';
/*
Create a new post or comment (depending on $activity["object"]["type"]),
@ -88,4 +89,18 @@ function scrub_object( $object ) {
unset( $object['bto'] );
return $object;
}
function make_create( $actor_slug, $object ) {
$actor = \actors\get_actor_by_slug( $actor_slug );
if ( is_wp_error( $actor ) ) {
return $actor;
}
$activity = array(
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Create',
'actor' => $actor,
'object' => $object
);
return $activity;
}
?>

View File

@ -2,6 +2,7 @@
namespace activities\delete;
require_once plugin_dir_path( __FILE__ ) . '../objects.php';
require_once plugin_dir_path( __FILE__ ) . '../actors.php';
function handle_outbox( $actor, $activity ) {
if ( !array_key_exists( 'object', $activity ) ) {
@ -66,4 +67,17 @@ function check_authorization( $activity ) {
}
return true;
}
function make_delete( $actor_slug, $object ) {
$actor = \actors\get_actor_by_slug( $actor_slug );
if ( is_wp_error( $actor ) ) {
return $actor;
}
return array(
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Delete',
'actor' => $actor,
'object' => $object
);
}
?>

View File

@ -26,7 +26,7 @@ function handle_outbox( $actor_slug, $activity ) {
array( 'status' => 400 )
);
}
$existing_object = \objects\get_object_by_actvitypub_id( $update_object['id'] );
$existing_object = \objects\get_object_by_activitypub_id( $update_object['id'] );
if ( is_wp_error( $existing_object ) ) {
return $existing_object;
}
@ -92,4 +92,17 @@ function check_authorization( $activity ) {
}
return true;
}
function make_update( $actor_slug, $object ) {
$actor = \actors\get_actor_by_slug( $actor_slug );
if ( is_wp_error( $actor ) ) {
return $actor;
}
return array(
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Update',
'actor' => $actor,
'object' => $object
);
}
?>

View File

@ -24,6 +24,7 @@ require_once plugin_dir_path( __FILE__ ) . 'activities/undo.php';
require_once plugin_dir_path( __FILE__ ) . '../util.php';
function handle_activity( $actor_slug, $activity ) {
// TODO verify the authenticity of the activity
$activity = \util\dereference_object( $activity );
if ( !array_key_exists( 'type', $activity ) ) {
return new \WP_Error(

View File

@ -145,25 +145,23 @@ function update_object( $object ) {
$res = $wpdb->update(
'pterotype_objects',
array( 'object' => $object_json ),
array( 'id' => $id ),
array( 'activitypub_id' => $object['id'] ),
'%s', '%d' );
if ( !$res ) {
return new \WP_Error(
'db_error', __( 'Failed to update object row', 'pterotype' )
);
}
$activites_res = $wpdb->query( $wpdb->prepare(
'
UPDATE pterotype_activities
SET activity = JSON_SET(activity, "$.object", %s)
WHERE activity->"$.object.id" = %s;
',
$object_json, $object['id']
$referencing_activities = $wpdb->get_results( $wpdb->prepare(
'SELECT * FROM pterotype_activities WHERE activity->"$.object.id" = %s',
$object['id']
) );
if ( $activities_res === false ) {
return new \WP_Error(
'db_error', __( 'Failed to update associated activities', 'pterotype' )
);
if ( $referencing_activities ) {
foreach ( $referencing_activities as $activity_row ) {
$activity = json_decode( $activity_row->activity, true );
$activity['object'] = $object;
\activities\persist_activity( $activity );
}
}
return $object;
}

View File

@ -182,16 +182,6 @@ function persist_activity( $actor_slug, $activity ) {
}
function wrap_object_in_create( $actor_slug, $object ) {
$actor = \actors\get_actor_by_slug( $actor_slug );
if ( is_wp_error( $actor ) ) {
return $actor;
}
$activity = array(
'@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Create',
'actor' => $actor,
'object' => $object
);
return $activity;
return \activities\create\make_create( $actor_slug, $object );
}
?>