mirror of
https://github.com/Automattic/wordpress-activitypub
synced 2024-10-18 14:23:31 +00:00
Improve User management (#703)
* Use an ActivityPub capability to better enable/disable ActivityPub support * split PRs * remove test hook * do not run migrations for new installs * fix unit tests * fix unit tests * remove abandoned schedule! * fix migration class * fix order * restructuring * remove follower migration * do not yet remove legacy followers * remove blog-user changes * use a const for the version number * add user tests and fix old ones * use a more generic async migrator * optimized test
This commit is contained in:
parent
96626c6438
commit
79f400d88a
12 changed files with 249 additions and 41 deletions
|
@ -21,6 +21,8 @@ use function Activitypub\site_supports_blocks;
|
|||
require_once __DIR__ . '/includes/compat.php';
|
||||
require_once __DIR__ . '/includes/functions.php';
|
||||
|
||||
\define( 'ACTIVITYPUB_PLUGIN_VERSION', '2.2.0' );
|
||||
|
||||
/**
|
||||
* Initialize the plugin constants.
|
||||
*/
|
||||
|
@ -101,6 +103,7 @@ function plugin_init() {
|
|||
}
|
||||
\add_action( 'plugins_loaded', __NAMESPACE__ . '\plugin_init' );
|
||||
|
||||
|
||||
/**
|
||||
* Class Autoloader
|
||||
*/
|
||||
|
@ -218,6 +221,10 @@ function get_plugin_meta( $default_headers = array() ) {
|
|||
* Plugin Version Number used for caching.
|
||||
*/
|
||||
function get_plugin_version() {
|
||||
if ( \defined( 'ACTIVITYPUB_PLUGIN_VERSION' ) ) {
|
||||
return ACTIVITYPUB_PLUGIN_VERSION;
|
||||
}
|
||||
|
||||
$meta = get_plugin_meta( array( 'Version' => 'Version' ) );
|
||||
|
||||
return $meta['Version'];
|
||||
|
|
|
@ -44,9 +44,6 @@ class Activity_Dispatcher {
|
|||
* @return void
|
||||
*/
|
||||
public static function send_activity_or_announce( $wp_object, $type ) {
|
||||
// check if a migration is needed before sending new posts
|
||||
Migration::maybe_migrate();
|
||||
|
||||
if ( is_user_type_disabled( 'blog' ) ) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ class Activitypub {
|
|||
\add_action( 'init', array( self::class, 'add_rewrite_rules' ), 11 );
|
||||
\add_action( 'init', array( self::class, 'theme_compat' ), 11 );
|
||||
|
||||
\add_action( 'user_register', array( self::class, 'user_register' ) );
|
||||
|
||||
\add_action( 'in_plugin_update_message-' . ACTIVITYPUB_PLUGIN_BASENAME, array( self::class, 'plugin_update_message' ) );
|
||||
|
||||
// register several post_types
|
||||
|
@ -455,4 +457,17 @@ class Activitypub {
|
|||
|
||||
\do_action( 'activitypub_after_register_post_type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the 'activitypub' query variable so WordPress won't mangle it.
|
||||
*
|
||||
* @param int $user_id User ID.
|
||||
* @param array $userdata The raw array of data passed to wp_insert_user().
|
||||
*/
|
||||
public static function user_register( $user_id ) {
|
||||
if ( \user_can( $user_id, 'publish_posts' ) ) {
|
||||
$user = \get_user_by( 'id', $user_id );
|
||||
$user->add_cap( 'activitypub' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,11 @@ class Admin {
|
|||
\add_action( 'admin_notices', array( self::class, 'admin_notices' ) );
|
||||
\add_filter( 'comment_row_actions', array( self::class, 'comment_row_actions' ), 10, 2 );
|
||||
|
||||
\add_filter( 'manage_users_columns', array( self::class, 'manage_users_columns' ), 10, 1 );
|
||||
\add_filter( 'manage_users_custom_column', array( self::class, 'manage_users_custom_column' ), 10, 3 );
|
||||
\add_filter( 'bulk_actions-users', array( self::class, 'user_bulk_options' ) );
|
||||
\add_filter( 'handle_bulk_actions-users', array( self::class, 'handle_bulk_request' ), 10, 3 );
|
||||
|
||||
if ( ! is_user_disabled( get_current_user_id() ) ) {
|
||||
\add_action( 'show_user_profile', array( self::class, 'add_profile' ) );
|
||||
}
|
||||
|
@ -345,4 +350,88 @@ class Admin {
|
|||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a column "activitypub"
|
||||
*
|
||||
* This column shows if the user has the capability to use ActivityPub.
|
||||
*
|
||||
* @param array $columns The columns.
|
||||
*
|
||||
* @return array The columns extended by the activitypub.
|
||||
*/
|
||||
public static function manage_users_columns( $columns ) {
|
||||
$columns['activitypub'] = __( 'ActivityPub Support', 'activitypub' );
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the results for the activitypub column.
|
||||
*
|
||||
* @param string $output Custom column output. Default empty.
|
||||
* @param string $column_name Column name.
|
||||
* @param int $user_id ID of the currently-listed user.
|
||||
*
|
||||
* @return string The column contents.
|
||||
*/
|
||||
public static function manage_users_custom_column( $output, $column_name, $user_id ) {
|
||||
if ( 'activitypub' !== $column_name ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
if ( \user_can( $user_id, 'activitypub' ) ) {
|
||||
return '✓';
|
||||
} else {
|
||||
return '✗';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add options to the Bulk dropdown on the users page
|
||||
*
|
||||
* @param array $actions The existing bulk options.
|
||||
*
|
||||
* @return array The extended bulk options.
|
||||
*/
|
||||
public static function user_bulk_options( $actions ) {
|
||||
$actions['add_activitypub_cap'] = __( 'Enable for ActivityPub', 'activitypub' );
|
||||
$actions['remove_activitypub_cap'] = __( 'Disable for ActivityPub', 'activitypub' );
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle bulk activitypub requests
|
||||
*
|
||||
* * `add_activitypub_cap` - Add the activitypub capability to the selected users.
|
||||
* * `remove_activitypub_cap` - Remove the activitypub capability from the selected users.
|
||||
*
|
||||
* @param string $sendback The URL to send the user back to.
|
||||
* @param string $action The requested action.
|
||||
* @param array $users The selected users.
|
||||
*
|
||||
* @return string The URL to send the user back to.
|
||||
*/
|
||||
public static function handle_bulk_request( $sendback, $action, $users ) {
|
||||
if (
|
||||
'remove_activitypub_cap' !== $action &&
|
||||
'add_activitypub_cap' !== $action
|
||||
) {
|
||||
return $sendback;
|
||||
}
|
||||
|
||||
foreach ( $users as $user_id ) {
|
||||
$user = new \WP_User( $user_id );
|
||||
if (
|
||||
'add_activitypub_cap' === $action &&
|
||||
user_can( $user_id, 'publish_posts' )
|
||||
) {
|
||||
$user->add_cap( 'activitypub' );
|
||||
} elseif ( 'remove_activitypub_cap' === $action ) {
|
||||
$user->remove_cap( 'activitypub' );
|
||||
}
|
||||
}
|
||||
|
||||
return $sendback;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,9 @@ class Migration {
|
|||
* Initialize the class, registering WordPress hooks
|
||||
*/
|
||||
public static function init() {
|
||||
\add_action( 'activitypub_schedule_migration', array( self::class, 'maybe_migrate' ) );
|
||||
\add_action( 'activitypub_migrate', array( self::class, 'async_migration' ) );
|
||||
|
||||
self::maybe_migrate();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -108,18 +110,28 @@ class Migration {
|
|||
|
||||
$version_from_db = self::get_version();
|
||||
|
||||
// check for inital migration
|
||||
if ( ! $version_from_db ) {
|
||||
self::add_default_settings();
|
||||
$version_from_db = self::get_target_version();
|
||||
}
|
||||
|
||||
// schedule the async migration
|
||||
if ( ! \wp_next_scheduled( 'activitypub_migrate', $version_from_db ) ) {
|
||||
\wp_schedule_single_event( \time(), 'activitypub_migrate', $version_from_db );
|
||||
}
|
||||
if ( version_compare( $version_from_db, '0.17.0', '<' ) ) {
|
||||
self::migrate_from_0_16();
|
||||
}
|
||||
if ( version_compare( $version_from_db, '1.0.0', '<' ) ) {
|
||||
self::migrate_from_0_17();
|
||||
}
|
||||
if ( version_compare( $version_from_db, '1.3.0', '<' ) ) {
|
||||
self::migrate_from_1_2_0();
|
||||
}
|
||||
if ( version_compare( $version_from_db, '2.1.0', '<' ) ) {
|
||||
self::migrate_from_2_0_0();
|
||||
}
|
||||
if ( version_compare( $version_from_db, '2.3.0', '<' ) ) {
|
||||
self::migrate_from_2_1_0();
|
||||
}
|
||||
|
||||
update_option( 'activitypub_db_version', self::get_target_version() );
|
||||
|
||||
|
@ -127,23 +139,14 @@ class Migration {
|
|||
}
|
||||
|
||||
/**
|
||||
* Updates the DB-schema of the followers-list
|
||||
* Asynchronously migrates the database structure.
|
||||
*
|
||||
* @return void
|
||||
* @param string $version_from_db The version from which to migrate.
|
||||
*/
|
||||
private static function migrate_from_0_17() {
|
||||
// migrate followers
|
||||
foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
|
||||
$followers = get_user_meta( $user_id, 'activitypub_followers', true );
|
||||
|
||||
if ( $followers ) {
|
||||
foreach ( $followers as $actor ) {
|
||||
Followers::add_follower( $user_id, $actor );
|
||||
}
|
||||
}
|
||||
public static function async_migration( $version_from_db ) {
|
||||
if ( version_compare( $version_from_db, '1.0.0', '<' ) ) {
|
||||
self::migrate_from_0_17();
|
||||
}
|
||||
|
||||
Activitypub::flush_rewrite_rules();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,13 +186,33 @@ class Migration {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the DB-schema of the followers-list
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function migrate_from_0_17() {
|
||||
// migrate followers
|
||||
foreach ( get_users( array( 'fields' => 'ID' ) ) as $user_id ) {
|
||||
$followers = get_user_meta( $user_id, 'activitypub_followers', true );
|
||||
|
||||
if ( $followers ) {
|
||||
foreach ( $followers as $actor ) {
|
||||
Followers::add_follower( $user_id, $actor );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Activitypub::flush_rewrite_rules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the cache after updating to 1.3.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function migrate_from_1_2_0() {
|
||||
$user_ids = get_users(
|
||||
$user_ids = \get_users(
|
||||
array(
|
||||
'fields' => 'ID',
|
||||
'capability__in' => array( 'publish_posts' ),
|
||||
|
@ -220,4 +243,45 @@ class Migration {
|
|||
\update_option( 'activitypub_object_type', 'wordpress-post-format' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the ActivityPub capability to all users that can publish posts
|
||||
* Delete old meta to store followers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function migrate_from_2_1_0() {
|
||||
// add the ActivityPub capability to all users that can publish posts
|
||||
self::add_activitypub_capability();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the defaults needed for the plugin to work
|
||||
*
|
||||
* * Add the ActivityPub capability to all users that can publish posts
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function add_default_settings() {
|
||||
self::add_activitypub_capability();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the ActivityPub capability to all users that can publish posts
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function add_activitypub_capability() {
|
||||
// get all WP_User objects that can publish posts
|
||||
$users = \get_users(
|
||||
array(
|
||||
'capability__in' => array( 'publish_posts' ),
|
||||
)
|
||||
);
|
||||
|
||||
// add ActivityPub capability to all users that can publish posts
|
||||
foreach ( $users as $user ) {
|
||||
$user->add_cap( 'activitypub' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,9 +64,6 @@ class Scheduler {
|
|||
\add_action( 'activitypub_update_followers', array( self::class, 'update_followers' ) );
|
||||
\add_action( 'activitypub_cleanup_followers', array( self::class, 'cleanup_followers' ) );
|
||||
|
||||
// Migration
|
||||
\add_action( 'admin_init', array( self::class, 'schedule_migration' ) );
|
||||
|
||||
// profile updates for blog options
|
||||
if ( ! is_user_type_disabled( 'blog' ) ) {
|
||||
\add_action( 'update_option_site_icon', array( self::class, 'blog_user_update' ) );
|
||||
|
@ -265,17 +262,6 @@ class Scheduler {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule migration if DB-Version is not up to date.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function schedule_migration() {
|
||||
if ( ! \wp_next_scheduled( 'activitypub_schedule_migration' ) && ! Migration::is_latest_version() ) {
|
||||
\wp_schedule_single_event( \time(), 'activitypub_schedule_migration' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a profile update when relevant user meta is updated.
|
||||
*
|
||||
|
@ -287,7 +273,7 @@ class Scheduler {
|
|||
*/
|
||||
public static function user_meta_update( $meta_id, $user_id, $meta_key ) {
|
||||
// don't bother if the user can't publish
|
||||
if ( ! \user_can( $user_id, 'publish_posts' ) ) {
|
||||
if ( ! \user_can( $user_id, 'activitypub' ) ) {
|
||||
return;
|
||||
}
|
||||
// the user meta fields that affect a profile.
|
||||
|
@ -311,7 +297,7 @@ class Scheduler {
|
|||
*/
|
||||
public static function user_update( $user_id ) {
|
||||
// don't bother if the user can't publish
|
||||
if ( ! \user_can( $user_id, 'publish_posts' ) ) {
|
||||
if ( ! \user_can( $user_id, 'activitypub' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ class Users {
|
|||
public static function get_collection() {
|
||||
$users = \get_users(
|
||||
array(
|
||||
'capability__in' => array( 'publish_posts' ),
|
||||
'capability__in' => array( 'activitypub' ),
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -384,7 +384,7 @@ function is_user_disabled( $user_id ) {
|
|||
break;
|
||||
}
|
||||
|
||||
if ( ! \user_can( $user_id, 'publish_posts' ) ) {
|
||||
if ( ! \user_can( $user_id, 'activitypub' ) ) {
|
||||
$return = true;
|
||||
break;
|
||||
}
|
||||
|
@ -644,7 +644,7 @@ function get_total_users() {
|
|||
|
||||
$users = \get_users(
|
||||
array(
|
||||
'capability__in' => array( 'publish_posts' ),
|
||||
'capability__in' => array( 'activitypub' ),
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -73,4 +73,11 @@
|
|||
<rule ref="WordPress.Arrays.ArrayDeclarationSpacing">
|
||||
<exclude-pattern>**/*.asset.php</exclude-pattern>
|
||||
</rule>
|
||||
<rule ref="WordPress.WP.Capabilities">
|
||||
<properties>
|
||||
<property name="custom_capabilities" type="array">
|
||||
<element value="activitypub" />
|
||||
</property>
|
||||
</properties>
|
||||
</rule>
|
||||
</ruleset>
|
||||
|
|
|
@ -29,3 +29,5 @@ function _manually_load_plugin() {
|
|||
// Start up the WP testing environment.
|
||||
require $_tests_dir . '/includes/bootstrap.php';
|
||||
require __DIR__ . '/class-activitypub-testcase-cache-http.php';
|
||||
|
||||
\Activitypub\Migration::add_default_settings();
|
||||
|
|
|
@ -271,6 +271,8 @@ class Test_Activitypub_Followers extends WP_UnitTestCase {
|
|||
}
|
||||
|
||||
public function test_migration() {
|
||||
update_option( 'activitypub_db_version', '0.0.1' );
|
||||
|
||||
$followers = array(
|
||||
'https://example.com/author/jon',
|
||||
'https://example.og/errors',
|
||||
|
@ -286,6 +288,12 @@ class Test_Activitypub_Followers extends WP_UnitTestCase {
|
|||
|
||||
\Activitypub\Migration::maybe_migrate();
|
||||
|
||||
$schedule = \wp_next_scheduled( 'activitypub_migrate', '0.0.1' );
|
||||
|
||||
$this->assertNotFalse( $schedule );
|
||||
|
||||
do_action( 'activitypub_migrate', '0.0.1' );
|
||||
|
||||
$db_followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
||||
|
||||
$this->assertCount( 3, $db_followers );
|
||||
|
|
33
tests/test-class-activitypub-user.php
Normal file
33
tests/test-class-activitypub-user.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
class Test_Activitypub_User extends WP_UnitTestCase {
|
||||
|
||||
public function test_activitypub_cap() {
|
||||
$userdata = array(
|
||||
'user_email' => 'subscriber@example.com',
|
||||
'first_name' => 'Max',
|
||||
'last_name' => 'Mustermann',
|
||||
'user_login' => 'subscriber',
|
||||
'user_pass' => 'subscriber',
|
||||
'role' => 'subscriber',
|
||||
);
|
||||
|
||||
$user_id = wp_insert_user( $userdata );
|
||||
$can = user_can( $user_id, 'activitypub' );
|
||||
|
||||
$this->assertFalse( $can );
|
||||
|
||||
$userdata = array(
|
||||
'user_email' => 'editor@example.com',
|
||||
'first_name' => 'Max',
|
||||
'last_name' => 'Mustermann',
|
||||
'user_login' => 'editor',
|
||||
'user_pass' => 'editor',
|
||||
'role' => 'editor',
|
||||
);
|
||||
|
||||
$user_id = wp_insert_user( $userdata );
|
||||
$can = user_can( $user_id, 'activitypub' );
|
||||
|
||||
$this->assertTrue( $can );
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue