Improve migration UX

This commit is contained in:
Django Doucet 2022-10-07 15:41:46 -06:00
parent ecbe724b82
commit 8707387ab8
6 changed files with 168 additions and 88 deletions

View file

@ -3,7 +3,7 @@
* Plugin Name: ActivityPub * Plugin Name: ActivityPub
* Plugin URI: https://github.com/pfefferle/wordpress-activitypub/ * Plugin URI: https://github.com/pfefferle/wordpress-activitypub/
* Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format. * Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format.
* Version: 0.13.4 * Version: 0.14.0-RC1
* Author: Matthias Pfefferle * Author: Matthias Pfefferle
* Author URI: https://notiz.blog/ * Author URI: https://notiz.blog/
* License: MIT * License: MIT

View file

@ -2,21 +2,53 @@
/** /**
* Reply Comment-edit screen * Reply Comment-edit screen
*/ */
if ( $('body').hasClass('edit-comments-php') ) {
//Insert Mentions into comment content on reply //Insert Mentions into comment content on reply
$('.comment-inline.button-link').on('click', function( event){ $( '.comment-inline.button-link' ).on( 'click', function( event ) {
// Summary/ContentWarning Syntax [CW] // Summary/ContentWarning Syntax [CW]
var summary = $(this).attr('data-summary') ? '[' + $(this).attr('data-summary') + '] ' : ''; var summary = $(this).attr('data-summary') ? '[' + $(this).attr('data-summary') + '] ' : '';
var recipients = $(this).attr('data-recipients') ? $(this).attr('data-recipients') + ' ' : ''; var recipients = $(this).attr('data-recipients') ? $(this).attr('data-recipients') + ' ' : '';
setTimeout(function() { setTimeout(function() {
if ( summary || recipients ){ if ( summary || recipients ){
$('#replycontent').val( summary + recipients ) $('#replycontent').val( summary + recipients )
} }
}, 100); }, 100);
}) })
//Clear Mentions from content on cancel //Clear Mentions from content on cancel
$('.cancel.button').on('click', function(){ $('.cancel.button').on('click', function(){
$('#replycontent').val(''); $('#replycontent').val('');
}); });
}
})( jQuery ); /**
* Tools screen
*/
if ( $('body').hasClass('tools_page_activitypub_tools') ) {
$('.delete_annouce' ).on('click', function(event) {
event.preventDefault();
var row = $(this).parents('tr') ? $(this).parents('tr') : '';
var nonce = $(this).attr('data-nonce') ? $(this).attr('data-nonce') : '';
var post_url = $(this).attr('data-post_url') ? $(this).attr('data-post_url') : '';
var post_author = $(this).attr('data-post_author') ? $(this).attr('data-post_author') : '';
var data = {
'action': 'migrate_post',
'nonce': nonce,
'post_url': post_url,
'post_author': post_author
}
$.ajax({
url: ajaxurl,
type: 'POST',
data: data,
success: function () {
row.remove()
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(textStatus + errorThrown);
}
})
});
}
})( jQuery );

View file

@ -15,7 +15,8 @@ class Admin {
\add_action( 'admin_init', array( '\Activitypub\Admin', 'register_settings' ) ); \add_action( 'admin_init', array( '\Activitypub\Admin', 'register_settings' ) );
\add_action( 'admin_init', array( '\Activitypub\Admin', 'version_check' ), 1 ); \add_action( 'admin_init', array( '\Activitypub\Admin', 'version_check' ), 1 );
\add_action( 'show_user_profile', array( '\Activitypub\Admin', 'add_fediverse_profile' ) ); \add_action( 'show_user_profile', array( '\Activitypub\Admin', 'add_fediverse_profile' ) );
\add_action( 'admin_enqueue_scripts', array( '\Activitypub\Admin', 'scripts_reply_comments' ), 10, 2 ); \add_action( 'admin_enqueue_scripts', array( '\Activitypub\Admin', 'enqueue_script_actions' ), 10, 2 );
\add_action( 'wp_ajax_migrate_post', array( '\Activitypub\Admin', 'migrate_post_action' ) );
\add_filter( 'comment_row_actions', array( '\Activitypub\Admin', 'reply_comments_actions' ), 10, 2 ); \add_filter( 'comment_row_actions', array( '\Activitypub\Admin', 'reply_comments_actions' ), 10, 2 );
} }
@ -144,21 +145,15 @@ class Admin {
$plugin_data = \get_plugin_data( ACTIVITYPUB_PLUGIN ); $plugin_data = \get_plugin_data( ACTIVITYPUB_PLUGIN );
$activitypub_db_version = \get_option( 'activitypub_version' ); $activitypub_db_version = \get_option( 'activitypub_version' );
// Needs update
if ( empty( $activitypub_db_version ) || \version_compare( $plugin_data['Version'], $activitypub_db_version, '>' ) ) { if ( empty( $activitypub_db_version ) || \version_compare( $plugin_data['Version'], $activitypub_db_version, '>' ) ) {
// Check for specific migrations // Check for specific migrations
if ( version_compare( '0.13.5', $activitypub_db_version, '>' ) ) { if ( version_compare( '0.13.4', $activitypub_db_version, '>' ) ) {
// This updates post_meta with _activitypub_permalink_compat.
// Posts that have this meta will be backwards compatible with their permalink based ActivityPub ID (URI)
// This may create false positives, where the permalink has changed (slug, permalink structure) since federation,
// for those cases a delete_url will allow for federating a delete based on the federated object ID (the old permalink)
\Activitypub\Tools\Posts::mark_posts_to_migrate(); \Activitypub\Tools\Posts::mark_posts_to_migrate();
} }
} }
\update_option( 'activitypub_version', $plugin_data['Version'] ); \update_option( 'activitypub_version', $plugin_data['Version'] );
//\delete_option( 'activitypub_version' );
} }
public static function add_settings_help_tab() { public static function add_settings_help_tab() {
@ -192,13 +187,35 @@ class Admin {
\Activitypub\get_identifier_settings( $user->ID ); \Activitypub\get_identifier_settings( $user->ID );
} }
public static function enqueue_script_actions( $hook ) {
if ( 'edit-comments.php' === $hook || 'tools_page_activitypub_tools' === $hook ) {
\wp_enqueue_script(
'activitypub_actions',
\plugin_dir_url( __FILE__ ) . '/activitypub.js',
array( 'jquery' ),
\filemtime( \plugin_dir_path( __FILE__ ) . '/activitypub.js' ),
true
);
}
}
/**
* Migrate post (Ajax)
*/
public static function migrate_post_action() {
if ( wp_verify_nonce( $_POST['nonce'], 'activitypub_migrate_actions' ) ) {
\Activitypub\Tools\Posts::migrate_post( rawurldecode( $_POST['post_url'] ), absint( $_POST['post_author'] ) );
\delete_post_meta( \url_to_postid( $_POST['post_url'] ), '_activitypub_permalink_compat' );
} else {
$error = new WP_Error( 'nonce_failure', __( 'Unauthorized', 'activitypub' ) );
wp_send_json_error( $error );
}
wp_die();
}
public static function reply_comments_actions( $actions, $comment ) { public static function reply_comments_actions( $actions, $comment ) {
//unset( $actions['reply'] );
$recipients = \Activitypub\get_recipients( $comment->comment_ID ); $recipients = \Activitypub\get_recipients( $comment->comment_ID );
$summary = \Activitypub\get_summary( $comment->comment_ID ); $summary = \Activitypub\get_summary( $comment->comment_ID );
//TODO revise for non-js reply action
// 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>'; $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( $actions['reply'] = \sprintf(
$reply_button, $reply_button,
@ -211,20 +228,6 @@ class Admin {
$summary, $summary,
\__( 'Reply', 'activitypub' ) \__( 'Reply', 'activitypub' )
); );
return $actions; return $actions;
} }
public static function scripts_reply_comments( $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
);
}
} }

View file

@ -33,8 +33,19 @@ class Posts {
'meta_key' => '_activitypub_permalink_compat', 'meta_key' => '_activitypub_permalink_compat',
'order' => 'ASC', 'order' => 'ASC',
); );
$posts_to_migrate = \get_posts( $args ); return \get_posts( $args );
return $posts_to_migrate; }
public static function get_posts_with_activitypub_comments() {
$args = array(
'comment_type' => 'activitypub',
);
$activitypub_comments = \get_comments( $args );
$activitypub_comments_posts = array();
foreach ( $activitypub_comments as $comment ) {
$activitypub_comments_posts[] = $comment->comment_post_ID;
}
return \get_posts( \array_unique( $activitypub_comments_posts ) );
} }
public static function count_posts_to_migrate() { public static function count_posts_to_migrate() {

View file

@ -6,12 +6,14 @@ if ( ! \class_exists( '\WP_List_Table' ) ) {
} }
class Migrate_List extends \WP_List_Table { class Migrate_List extends \WP_List_Table {
public function get_columns() { public function get_columns() {
return array( return array(
'cb' => '<input type="checkbox" />',
'post_author' => \__( 'Post Author (user_id)', 'activitypub' ), 'post_author' => \__( 'Post Author (user_id)', 'activitypub' ),
'title' => \__( 'Post', 'activitypub' ), 'title' => \__( 'Post', 'activitypub' ),
'date' => \__( 'Publication Date', 'activitypub' ),
'comments' => \__( 'Comments', 'activitypub' ), 'comments' => \__( 'Comments', 'activitypub' ),
'date' => \__( 'Publication Date', 'activitypub' ),
'migrate' => \__( 'Migrate', 'activitypub' ), 'migrate' => \__( 'Migrate', 'activitypub' ),
); );
} }
@ -36,8 +38,8 @@ class Migrate_List extends \WP_List_Table {
\get_permalink( $post->ID ), \get_permalink( $post->ID ),
$post->post_title $post->post_title
), ),
'date' => $post->post_date,
'comments' => $post->comment_count, 'comments' => $post->comment_count,
'date' => $post->post_date,
'migrate' => \get_post_meta( $post->ID, '_activitypub_permalink_compat', true ), 'migrate' => \get_post_meta( $post->ID, '_activitypub_permalink_compat', true ),
); );
} }
@ -60,21 +62,39 @@ class Migrate_List extends \WP_List_Table {
$nonce = \esc_attr( $_REQUEST['_wpnonce'] ); $nonce = \esc_attr( $_REQUEST['_wpnonce'] );
} }
// delete // delete
if ( isset( $_REQUEST['action'] ) && 'activitypub_tools' === $_REQUEST['page'] && 'delete' === $_REQUEST['action'] ) { if ( isset( $_REQUEST['action'] ) && 'activitypub_tools' === $_REQUEST['page'] && 'delete_notice' === $_REQUEST['action'] ) {
if ( wp_verify_nonce( $nonce, 'activitypub_delete_post' ) ) { if ( wp_verify_nonce( $nonce, 'activitypub_migrate_actions' ) ) {
\Activitypub\Tools\Posts::delete_url( rawurldecode( $_REQUEST['post_url'] ), absint( $_REQUEST['post_author'] ) ); //\Activitypub\Tools\Posts::delete_url( rawurldecode( $_REQUEST['post_url'] ), absint( $_REQUEST['post_author'] ) );
\delete_post_meta( \url_to_postid( $_REQUEST['post_url'] ), '_activitypub_permalink_compat' ); \delete_post_meta( \url_to_postid( $_REQUEST['post_url'] ), '_activitypub_permalink_compat' );
} }
} }
// delete and announce // delete and announce
if ( isset( $_REQUEST['action'] ) && 'activitypub_tools' === $_REQUEST['page'] && 'delete_announce' === $_REQUEST['action'] ) { if ( isset( $_REQUEST['action'] ) && 'activitypub_tools' === $_REQUEST['page'] && 'delete' === $_REQUEST['action'] ) {
if ( wp_verify_nonce( $nonce, 'activitypub_delete_announce_post' ) ) { if ( wp_verify_nonce( $nonce, 'activitypub_migrate_actions' ) ) {
\Activitypub\Tools\Posts::migrate_post( rawurldecode( $_REQUEST['post_url'] ), absint( $_REQUEST['post_author'] ) ); \Activitypub\Tools\Posts::migrate_post( rawurldecode( $_REQUEST['post_url'] ), absint( $_REQUEST['post_author'] ) );
\delete_post_meta( \url_to_postid( $_REQUEST['post_url'] ), '_activitypub_permalink_compat' ); \delete_post_meta( \url_to_postid( $_REQUEST['post_url'] ), '_activitypub_permalink_compat' );
} }
} }
} }
public function single_row( $item ) {
$inline_styles = ( $item['comments'] > 0 ) ? 'warning' : ''; ?>
<tr class="<?php echo $inline_styles; ?>"><?php $this->single_row_columns( $item ); ?></tr><?php
}
/**
* Render the bulk edit checkbox
*
* @param array $item
*
* @return string
*/
function column_cb( $item ) {
return sprintf(
'<input type="checkbox" name="selected[]" value="%s" />', $item['migrate']
);
}
/** /**
* Render a column when no column specific method exists. * Render a column when no column specific method exists.
* *
@ -85,10 +105,11 @@ class Migrate_List extends \WP_List_Table {
*/ */
public function column_default( $item, $column_name ) { public function column_default( $item, $column_name ) {
switch ( $column_name ) { switch ( $column_name ) {
case 'cb':
case 'post_author': case 'post_author':
case 'title': case 'title':
case 'date':
case 'comments': case 'comments':
case 'date':
case 'migrate': case 'migrate':
return $item[ $column_name ]; return $item[ $column_name ];
default: default:
@ -97,29 +118,36 @@ class Migrate_List extends \WP_List_Table {
} }
public function column_title( $item ) { public function column_title( $item ) {
$delete_announce_nonce = wp_create_nonce( 'activitypub_delete_announce_post' ); $migrate_action_nonce = wp_create_nonce( 'activitypub_migrate_actions' );
$delete_nonce = wp_create_nonce( 'activitypub_delete_post' );
$actions = array( $actions = array(
'delete_announce' => sprintf(
'<a href="?page=%s&action=%s&post_author=%s&post_url=%s&_wpnonce=%s" title="%s">%s</a>',
esc_attr( $_REQUEST['page'] ),
'delete_announce',
$item['post_author'],
\rawurlencode( $item['migrate'] ),
$delete_announce_nonce,
__( 'Delete the federated post, and re-share the original post', 'activitypub' ),
__( 'Delete & Re-share original', 'activitypub' )
),
'delete' => sprintf( 'delete' => sprintf(
'<a href="?page=%s&action=%s&post_author=%s&post_url=%s&_wpnonce=%s" title="%s">%s</a>', '<a href="?page=%s&action=%s&post_author=%s&post_url=%s&_wpnonce=%s" class="%s" title="%s" data-post_author="%s" data-post_url="%s" data-nonce="%s">%s</a>',
esc_attr( $_REQUEST['page'] ), esc_attr( $_REQUEST['page'] ),
'delete', 'delete',// using this id for style reasons
$item['post_author'], $item['post_author'],
\rawurlencode( $item['migrate'] ), \rawurlencode( $item['migrate'] ),
$delete_nonce, $migrate_action_nonce,
__( 'Delete the federated post', 'activitypub' ), 'delete_annouce aria-button-ui-if-js',
__( 'Delete', 'activitypub' ) __( 'Delete the federated post, and re-share the post with a new id', 'activitypub' ),
$item['post_author'],
\rawurlencode( $item['migrate'] ),
$migrate_action_nonce,
__( 'Migrate post', 'activitypub' )
),
'delete_notice' => sprintf(
'<a href="?page=%s&action=%s&post_author=%s&post_url=%s&_wpnonce=%s" class="%s" title="%s" data-post_author="%s" data-post_url="%s" data-nonce="%s">%s</a>',
esc_attr( $_REQUEST['page'] ),
'delete_notice',
$item['post_author'],
\rawurlencode( $item['migrate'] ),
$migrate_action_nonce,
'delete aria-button-ui-if-js',
__( 'Delete this notice and backwards compatibility', 'activitypub' ),
$item['post_author'],
\rawurlencode( $item['migrate'] ),
$migrate_action_nonce,
__( 'Remove notice', 'activitypub' )
), ),
); );
return sprintf( '%1$s %2$s', $item['title'], $this->row_actions( $actions, true ) ); return sprintf( '%1$s %2$s', $item['title'], $this->row_actions( $actions, true ) );

View file

@ -10,26 +10,32 @@ if ( isset( $_REQUEST['post_url'] ) && $_REQUEST['page'] == "activitypub_tools"
} }
?> ?>
<div class="wrap"> <div class="wrap">
<h1><?php \esc_html_e( 'Migrate posts (Fediverse)', 'activitypub' ); ?></h1> <h1><?php \esc_html_e( 'Manage ActivityPub posts (Fediverse)', 'activitypub' ); ?></h1>
<p><?php \printf( <?php if ( \Activitypub\Tools\Posts::count_posts_to_migrate() > 0 ): ?>
\__( 'You currently have %s posts to migrate.', 'activitypub' ),
\esc_attr( \Activitypub\Tools\Posts::count_posts_to_migrate() )
); ?></p>
<p><?php \printf( <div class="notice notice-warning">
\__( 'Posts with ActivityPub Comments, should be treated with care, existing interactions in the fediverse but not on site will be lost.', 'activitypub' ), <p><?php \printf(
\esc_attr( \Activitypub\Tools\Posts::count_posts_to_migrate() ) \__( 'The following table lists ActivityPub posts which have been marked as backwards compatible, and ready for migration. <br>
); ?></p> Migration here means updating the Activity ID by federating a Delete activity removing the original post from the fediverse, and then Sharing the new post ID with an Announce activity. <br>
Posts with comments should be treated with care, existing interactions in the fediverse will be lost.', 'activitypub' ),
\esc_attr( \Activitypub\Tools\Posts::count_posts_to_migrate() )
); ?></p>
</div>
<?php $token_table = new \Activitypub\Table\Migrate_List(); ?> <p><?php \printf(
\__( 'You currently have %s posts to migrate.', 'activitypub' ),
\esc_attr( \Activitypub\Tools\Posts::count_posts_to_migrate() )
); ?></p>
<form method="POST" id="table"> <?php $token_table = new \Activitypub\Table\Migrate_List(); ?>
<?php <form method="POST" id="table">
$token_table->prepare_items(); <?php
$token_table->display(); $token_table->prepare_items();
?> $token_table->display();
</form> ?>
</form>
<?php endif; ?>
<hr class="separator"> <hr class="separator">
<form method="POST" id="delete"> <form method="POST" id="delete">
<div> <div>