From 8707387ab8199d67ccf74c6efd274b79b5a96f74 Mon Sep 17 00:00:00 2001 From: Django Doucet Date: Fri, 7 Oct 2022 15:41:46 -0600 Subject: [PATCH] Improve migration UX --- activitypub.php | 2 +- includes/activitypub.js | 66 +++++++++++++++++++++------- includes/class-admin.php | 57 ++++++++++++------------ includes/class-tools.php | 15 ++++++- includes/table/migrate-list.php | 78 ++++++++++++++++++++++----------- templates/tools-page.php | 38 +++++++++------- 6 files changed, 168 insertions(+), 88 deletions(-) diff --git a/activitypub.php b/activitypub.php index fd27972..1d41c89 100644 --- a/activitypub.php +++ b/activitypub.php @@ -3,7 +3,7 @@ * Plugin Name: 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. - * Version: 0.13.4 + * Version: 0.14.0-RC1 * Author: Matthias Pfefferle * Author URI: https://notiz.blog/ * License: MIT diff --git a/includes/activitypub.js b/includes/activitypub.js index 655be51..4700c00 100644 --- a/includes/activitypub.js +++ b/includes/activitypub.js @@ -2,21 +2,53 @@ /** * Reply Comment-edit screen */ - - //Insert Mentions into comment content on reply - $('.comment-inline.button-link').on('click', function( event){ - // Summary/ContentWarning Syntax [CW] - var summary = $(this).attr('data-summary') ? '[' + $(this).attr('data-summary') + '] ' : ''; - var recipients = $(this).attr('data-recipients') ? $(this).attr('data-recipients') + ' ' : ''; - setTimeout(function() { - if ( summary || recipients ){ - $('#replycontent').val( summary + recipients ) - } - }, 100); - }) - //Clear Mentions from content on cancel - $('.cancel.button').on('click', function(){ - $('#replycontent').val(''); - }); + if ( $('body').hasClass('edit-comments-php') ) { + //Insert Mentions into comment content on reply + $( '.comment-inline.button-link' ).on( 'click', function( event ) { + // Summary/ContentWarning Syntax [CW] + var summary = $(this).attr('data-summary') ? '[' + $(this).attr('data-summary') + '] ' : ''; + var recipients = $(this).attr('data-recipients') ? $(this).attr('data-recipients') + ' ' : ''; + setTimeout(function() { + if ( summary || recipients ){ + $('#replycontent').val( summary + recipients ) + } + }, 100); + }) + //Clear Mentions from content on cancel + $('.cancel.button').on('click', function(){ + $('#replycontent').val(''); + }); + } -})( jQuery ); \ No newline at end of file + /** + * 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 ); diff --git a/includes/class-admin.php b/includes/class-admin.php index c662a01..5144537 100644 --- a/includes/class-admin.php +++ b/includes/class-admin.php @@ -15,7 +15,8 @@ class Admin { \add_action( 'admin_init', array( '\Activitypub\Admin', 'register_settings' ) ); \add_action( 'admin_init', array( '\Activitypub\Admin', 'version_check' ), 1 ); \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 ); } @@ -144,21 +145,15 @@ class Admin { $plugin_data = \get_plugin_data( ACTIVITYPUB_PLUGIN ); $activitypub_db_version = \get_option( 'activitypub_version' ); - // Needs update if ( empty( $activitypub_db_version ) || \version_compare( $plugin_data['Version'], $activitypub_db_version, '>' ) ) { // Check for specific migrations - if ( version_compare( '0.13.5', $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) - + if ( version_compare( '0.13.4', $activitypub_db_version, '>' ) ) { \Activitypub\Tools\Posts::mark_posts_to_migrate(); } } \update_option( 'activitypub_version', $plugin_data['Version'] ); + //\delete_option( 'activitypub_version' ); } public static function add_settings_help_tab() { @@ -192,13 +187,35 @@ class Admin { \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 ) { - //unset( $actions['reply'] ); $recipients = \Activitypub\get_recipients( $comment->comment_ID ); $summary = \Activitypub\get_summary( $comment->comment_ID ); - - //TODO revise for non-js reply action - // Public Reply $reply_button = ''; $actions['reply'] = \sprintf( $reply_button, @@ -211,20 +228,6 @@ class Admin { $summary, \__( 'Reply', 'activitypub' ) ); - 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 - ); - } } diff --git a/includes/class-tools.php b/includes/class-tools.php index 7ba6a29..1cf6538 100644 --- a/includes/class-tools.php +++ b/includes/class-tools.php @@ -33,8 +33,19 @@ class Posts { 'meta_key' => '_activitypub_permalink_compat', 'order' => 'ASC', ); - $posts_to_migrate = \get_posts( $args ); - return $posts_to_migrate; + return \get_posts( $args ); + } + + 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() { diff --git a/includes/table/migrate-list.php b/includes/table/migrate-list.php index 79a737b..cdddfbc 100644 --- a/includes/table/migrate-list.php +++ b/includes/table/migrate-list.php @@ -6,12 +6,14 @@ if ( ! \class_exists( '\WP_List_Table' ) ) { } class Migrate_List extends \WP_List_Table { + public function get_columns() { return array( + 'cb' => '', 'post_author' => \__( 'Post Author (user_id)', 'activitypub' ), 'title' => \__( 'Post', 'activitypub' ), - 'date' => \__( 'Publication Date', 'activitypub' ), 'comments' => \__( 'Comments', 'activitypub' ), + 'date' => \__( 'Publication Date', 'activitypub' ), 'migrate' => \__( 'Migrate', 'activitypub' ), ); } @@ -36,8 +38,8 @@ class Migrate_List extends \WP_List_Table { \get_permalink( $post->ID ), $post->post_title ), - 'date' => $post->post_date, 'comments' => $post->comment_count, + 'date' => $post->post_date, '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'] ); } // delete - if ( isset( $_REQUEST['action'] ) && 'activitypub_tools' === $_REQUEST['page'] && 'delete' === $_REQUEST['action'] ) { - if ( wp_verify_nonce( $nonce, 'activitypub_delete_post' ) ) { - \Activitypub\Tools\Posts::delete_url( rawurldecode( $_REQUEST['post_url'] ), absint( $_REQUEST['post_author'] ) ); + if ( isset( $_REQUEST['action'] ) && 'activitypub_tools' === $_REQUEST['page'] && 'delete_notice' === $_REQUEST['action'] ) { + if ( wp_verify_nonce( $nonce, 'activitypub_migrate_actions' ) ) { + //\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 and announce - if ( isset( $_REQUEST['action'] ) && 'activitypub_tools' === $_REQUEST['page'] && 'delete_announce' === $_REQUEST['action'] ) { - if ( wp_verify_nonce( $nonce, 'activitypub_delete_announce_post' ) ) { + if ( isset( $_REQUEST['action'] ) && 'activitypub_tools' === $_REQUEST['page'] && 'delete' === $_REQUEST['action'] ) { + if ( wp_verify_nonce( $nonce, 'activitypub_migrate_actions' ) ) { \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' ); } } } + public function single_row( $item ) { + $inline_styles = ( $item['comments'] > 0 ) ? 'warning' : ''; ?> + single_row_columns( $item ); ?>', $item['migrate'] + ); + } + /** * 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 ) { switch ( $column_name ) { + case 'cb': case 'post_author': case 'title': - case 'date': case 'comments': + case 'date': case 'migrate': return $item[ $column_name ]; default: @@ -97,29 +118,36 @@ class Migrate_List extends \WP_List_Table { } public function column_title( $item ) { - $delete_announce_nonce = wp_create_nonce( 'activitypub_delete_announce_post' ); - $delete_nonce = wp_create_nonce( 'activitypub_delete_post' ); + $migrate_action_nonce = wp_create_nonce( 'activitypub_migrate_actions' ); $actions = array( - 'delete_announce' => sprintf( - '%s', - 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( - '%s', + '%s', esc_attr( $_REQUEST['page'] ), - 'delete', + 'delete',// using this id for style reasons $item['post_author'], \rawurlencode( $item['migrate'] ), - $delete_nonce, - __( 'Delete the federated post', 'activitypub' ), - __( 'Delete', 'activitypub' ) + $migrate_action_nonce, + 'delete_annouce aria-button-ui-if-js', + __( '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( + '%s', + 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 ) ); diff --git a/templates/tools-page.php b/templates/tools-page.php index 6658911..37291a7 100644 --- a/templates/tools-page.php +++ b/templates/tools-page.php @@ -10,26 +10,32 @@ if ( isset( $_REQUEST['post_url'] ) && $_REQUEST['page'] == "activitypub_tools" } ?>
-

+

-

+ 0 ): ?> -

+
+

+ 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.
+ 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() ) + ); ?>

+
- +

-
- prepare_items(); - $token_table->display(); - ?> -
+ +
+ prepare_items(); + $token_table->display(); + ?> +
+