Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/user discrepancies display #100

Merged
merged 3 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 39 additions & 28 deletions includes/class-users.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Users {
*/
public static function init() {
add_filter( 'manage_users_columns', [ __CLASS__, 'manage_users_columns' ] );
add_filter( 'manage_users_custom_column', [ __CLASS__, 'manage_users_custom_column' ], 10, 3 );
add_filter( 'manage_users_custom_column', [ __CLASS__, 'manage_users_custom_column' ], 99, 3 ); // priority must be higher than Jetpack's jetpack_show_connection_status (10).
add_filter( 'users_list_table_query_args', [ __CLASS__, 'users_list_table_query_args' ] );
}

Expand All @@ -30,9 +30,7 @@ public static function init() {
* @return array
*/
public static function manage_users_columns( $columns ) {
if ( Site_Role::is_hub() ) {
$columns['newspack_network_activity'] = __( 'Newspack Network Activity', 'newspack-network' );
}
$columns['newspack_network_activity'] = __( 'Newspack Network Activity', 'newspack-network' );
if ( \Newspack_Network\Admin::use_experimental_auditing_features() ) {
$columns['newspack_network_user'] = __( 'Network Original User', 'newspack-network' );
}
Expand Down Expand Up @@ -60,36 +58,45 @@ public static function manage_users_custom_column( $value, $column_name, $user_i
);
}
}
if ( 'newspack_network_activity' === $column_name && Site_Role::is_hub() ) {
if ( 'newspack_network_activity' === $column_name ) {
$user = get_user_by( 'id', $user_id );
if ( ! $user ) {
return $value;
}
if ( Site_Role::is_hub() ) {
$last_activity = \Newspack_Network\Hub\Stores\Event_Log::get( [ 'email' => $user->user_email ], 1 );
if ( empty( $last_activity ) ) {
return '-';
}

$last_activity = \Newspack_Network\Hub\Stores\Event_Log::get( [ 'email' => $user->user_email ], 1 );

if ( empty( $last_activity ) ) {
return '-';
$event_log_url = add_query_arg(
[
'page' => EVENT_LOG_PAGE_SLUG,
'email' => urlencode( $user->user_email ),
],
admin_url( 'admin.php' )
);
return sprintf(
'%s: <code>%s</code><br><a href="%s">%s</a>',
__( 'Last Activity', 'newspack-network' ),
$last_activity[0]->get_summary(),
$event_log_url,
__( 'View all', 'newspack-network' )
);
} else {
$event_log_url = add_query_arg(
[
'page' => EVENT_LOG_PAGE_SLUG,
'email' => urlencode( $user->user_email ),
],
untrailingslashit( Node\Settings::get_hub_url() ) . '/wp-admin/admin.php'
);
return sprintf(
'<a href="%s">%s</a>',
$event_log_url,
__( 'View activity', 'newspack-network' )
);
}

$last_activity = $last_activity[0];

$summary = $last_activity->get_summary();
$event_log_url = add_query_arg(
[
'page' => EVENT_LOG_PAGE_SLUG,
'email' => $user->user_email,
],
admin_url( 'admin.php' )
);
return sprintf(
'%s: <code>%s</code><br><a href="%s">%s</a>',
__( 'Last Activity', 'newspack-network' ),
$summary,
$event_log_url,
__( 'View all', 'newspack-network' )
);

}
return $value;
}
Expand All @@ -106,6 +113,10 @@ public static function users_list_table_query_args( $args ) {
$args['role__in'] = explode( ',', sanitize_text_field( $_REQUEST['role__in'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
unset( $args['role'] );
}
if ( isset( $_REQUEST['role__not_in'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$args['role__not_in'] = explode( ',', sanitize_text_field( $_REQUEST['role__not_in'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
unset( $args['role'] );
}
return $args;
}
}
79 changes: 76 additions & 3 deletions includes/hub/admin/class-nodes-list.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ public static function init() {
add_action( 'admin_bar_menu', [ __CLASS__, 'admin_bar_menu' ], 100 );
}

/**
* Cache for site info responses.
*
* @var array
*/
private static $node_site_info_cache = [];

/**
* Cache for Hub site info.
*
* @var array
*/
private static $hub_site_info = false;

/**
* Modify columns on post type table
*
Expand All @@ -37,16 +51,32 @@ public static function posts_columns( $columns ) {
unset( $columns['date'] );
unset( $columns['stats'] );
if ( \Newspack_Network\Admin::use_experimental_auditing_features() ) {
$sync_users_count = \Newspack_Network\Utils\Users::get_synchronized_users_count();
$sync_users_info = sprintf(
' <span class="dashicons dashicons-info-outline" title="%s"></span>',
sprintf(
/* translators: list of user roles which will entail synchronization */
esc_attr__( 'Users with the following roles: %1$s (%2$d on the Hub)', 'newspack-network' ),
implode( ', ', \Newspack_Network\Utils\Users::get_synced_user_roles() ),
\Newspack_Network\Utils\Users::get_synchronized_users_count()
$sync_users_count
)
);
/* translators: %d is the synchronizable users count. */
$columns['sync_users'] = sprintf( __( 'Synchronizable Users (%d)', 'newspack-network' ), $sync_users_count ) . $sync_users_info;
if ( isset( $_GET['_newspack_user_discrepancies'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$columns['user_discrepancies'] = __( 'Discrepancies in Sync. Users', 'newspack-network' );
}

$not_sync_users_info = sprintf(
' <span class="dashicons dashicons-info-outline" title="%s"></span>',
sprintf(
/* translators: list of user roles which will entail synchronization */
esc_attr__( 'Users with roles different than the following roles: %1$s (%2$d on the Hub)', 'newspack-network' ),
implode( ', ', \Newspack_Network\Utils\Users::get_synced_user_roles() ),
\Newspack_Network\Utils\Users::get_not_synchronized_users_count()
)
);
$columns['sync_users'] = __( 'Synchronizable Users', 'newspack-network' ) . $sync_users_info;
$columns['not_sync_users'] = __( 'Non-synchronizable Users', 'newspack-network' ) . $not_sync_users_info;
}
$columns['links'] = __( 'Links', 'newspack-network' );
return $columns;
Expand Down Expand Up @@ -80,6 +110,38 @@ function ( $bookmark ) {
</p>
<?php
}
if ( ! isset( self::$node_site_info_cache[ $post_id ] ) ) {
self::$node_site_info_cache[ $post_id ] = $node->get_site_info();
}
$node_site_info = self::$node_site_info_cache[ $post_id ];

if ( isset( $_GET['_newspack_user_discrepancies'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( ! self::$hub_site_info ) {
self::$hub_site_info = [
'sync_user_emails' => \Newspack_Network\Utils\Users::get_synchronized_users_emails(),
];
}

// Display user discrepancies.
$node_users_emails = $node_site_info->sync_users_emails ?? [];
// Users who are on the Hub but not on the Node.
$not_on_node = array_diff( self::$hub_site_info['sync_user_emails'], $node_users_emails );
// Users who are not on the Node but are on the Hub.
$not_on_hub = array_diff( $node_users_emails, self::$hub_site_info['sync_user_emails'] );
if ( 'user_discrepancies' === $column ) {
?>
<span>
<?php
echo esc_html(
/* translators: %d - users on the Hub only, %d on the Node only */
sprintf( __( '%1$d on the Hub only, %2$d on the Node only', 'newspack-network' ), count( $not_on_node ), count( $not_on_hub ) )
);
?>
</span>
<?php
}
}

if ( 'sync_users' === $column ) {
$users_link = add_query_arg(
[
Expand All @@ -88,7 +150,18 @@ function ( $bookmark ) {
trailingslashit( $node->get_url() ) . 'wp-admin/users.php'
);
?>
<a href="<?php echo esc_url( $users_link ); ?>"><?php echo esc_html( $node->get_sync_users_count() ); ?></a>
<a href="<?php echo esc_url( $users_link ); ?>"><?php echo esc_html( $node_site_info->sync_users_count ?? 0 ); ?></a>
<?php
}
if ( 'not_sync_users' === $column ) {
$users_link = add_query_arg(
[
'role__not_in' => implode( ',', \Newspack_Network\Utils\Users::get_synced_user_roles() ),
],
trailingslashit( $node->get_url() ) . 'wp-admin/users.php'
);
?>
<a href="<?php echo esc_url( $users_link ); ?>"><?php echo esc_html( $node_site_info->not_sync_users_count ?? 0 ); ?></a>
<?php
}
}
Expand Down
10 changes: 1 addition & 9 deletions includes/hub/class-node.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public function get_bookmarks() {
/**
* Get site info.
*/
private function get_site_info() {
public function get_site_info() {
$response = wp_remote_get( // phpcs:ignore
$this->get_url() . '/wp-json/newspack-network/v1/info',
[
Expand All @@ -183,12 +183,4 @@ private function get_site_info() {
);
return json_decode( wp_remote_retrieve_body( $response ) );
}

/**
* Get synchronized users count.
*/
public function get_sync_users_count() {
$site_info = $this->get_site_info();
return $site_info->sync_users_count ?? 0;
}
}
6 changes: 5 additions & 1 deletion includes/node/class-info-endpoints.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ public static function register_routes() {
public static function handle_info_request() {
return rest_ensure_response(
[
'sync_users_count' => \Newspack_Network\Utils\Users::get_synchronized_users_count(),
'sync_users_count' => \Newspack_Network\Utils\Users::get_synchronized_users_count(),
'sync_users_emails' => \Newspack_Network\Utils\Users::get_synchronized_users_emails(),
'not_sync_users_count' => \Newspack_Network\Utils\Users::get_not_synchronized_users_count(),
'not_sync_users_emails' => \Newspack_Network\Utils\Users::get_not_synchronized_users_emails(),
'no_role_users_emails' => \Newspack_Network\Utils\Users::get_no_role_users_emails(),
]
);
}
Expand Down
61 changes: 58 additions & 3 deletions includes/utils/class-users.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,68 @@ public static function get_synced_user_roles() {
* Get synchronized users count.
*/
public static function get_synchronized_users_count() {
$users = get_users(
return count( self::get_synchronized_users( [ 'id' ] ) );
}

/**
* Get synchronized users emails.
*/
public static function get_synchronized_users_emails() {
return array_map( 'strtolower', array_column( self::get_synchronized_users( [ 'user_email' ] ), 'user_email' ) );
}

/**
* Get no-role users emails.
*/
public static function get_no_role_users_emails() {
global $wpdb;
$no_role_users_emails = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
"SELECT user_email FROM wp_users WHERE ID IN (SELECT user_id FROM wp_usermeta WHERE meta_key = 'wp_capabilities' AND (meta_value = 'a:0:{}' OR meta_value = '')) OR ID NOT IN (SELECT user_id FROM wp_usermeta WHERE meta_key = 'wp_capabilities')"
);
return array_map( 'strtolower', array_column( $no_role_users_emails, 'user_email' ) );
}

/**
* Get synchronized users.
*
* @param array $fields Fields to return.
*/
public static function get_synchronized_users( $fields = [] ) {
return get_users(
[
'role__in' => self::get_synced_user_roles(),
'fields' => [ 'id' ],
'fields' => $fields,
'number' => -1,
]
);
return count( $users );
}

/**
* Get not synchronized users count.
*
* @param array $fields Fields to return.
*/
public static function get_not_synchronized_users( $fields = [] ) {
return get_users(
[
'role__not_in' => self::get_synced_user_roles(),
'fields' => $fields,
'number' => -1,
]
);
}

/**
* Get synchronized users emails.
*/
public static function get_not_synchronized_users_emails() {
return array_map( 'strtolower', array_column( self::get_not_synchronized_users( [ 'user_email' ] ), 'user_email' ) );
}

/**
* Get not synchronized users count.
*/
public static function get_not_synchronized_users_count() {
return count( self::get_not_synchronized_users( [ 'id' ] ) );
}
}
8 changes: 6 additions & 2 deletions includes/woocommerce-memberships/class-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,18 @@ public static function init() {
/**
* Get active members' emails.
*
* @param \WC_Memberships_Membership_Plan $plan the membership plan.
* @param \WC_Memberships_Membership_Plan $plan The membership plan.
*/
public static function get_active_members_emails( $plan ) {
$active_memberships = $plan->get_memberships( [ 'post_status' => 'wcm-active' ] );
return array_map(
function ( $membership ) {
$user = get_user_by( 'id', $membership->get_user_id() );
return $user->user_email;
if ( $user ) {
return strtolower( $user->user_email );
} else {
return '';
}
},
$active_memberships
);
Expand Down