← All changes
|
jetpack_vendor/automattic/jetpack-connection/src/sso/class-user-admin.php
+169
-155
13.6.2
→
16.3
View file →
| @@ -10,8 +10,9 @@ | ||
| 10 | 10 | use Automattic\Jetpack\Assets; |
| 11 | 11 | use Automattic\Jetpack\Connection\Client; |
| 12 | 12 | use Automattic\Jetpack\Connection\Manager; |
| 13 | 13 | use Automattic\Jetpack\Connection\Package_Version; |
| 14 | +use Automattic\Jetpack\Connection\Users_Connection_Admin as Base_Admin; | |
| 14 | 15 | use Automattic\Jetpack\Roles; |
| 15 | 16 | use Automattic\Jetpack\Status\Host; |
| 16 | 17 | use Automattic\Jetpack\Tracking; |
| 17 | 18 | use WP_Error; |
| @@ -17,12 +18,18 @@ | ||
| 17 | 18 | use WP_Error; |
| 18 | 19 | use WP_User; |
| 19 | 20 | use WP_User_Query; |
| 20 | 21 | |
| 22 | +if ( ! defined( 'ABSPATH' ) ) { | |
| 23 | + exit( 0 ); | |
| 24 | +} | |
| 25 | + | |
| 21 | 26 | /** |
| 22 | 27 | * Jetpack sso user admin class. |
| 28 | + * | |
| 29 | + * @phan-constructor-used-for-side-effects | |
| 23 | 30 | */ |
| 24 | -class User_Admin { | |
| 31 | +class User_Admin extends Base_Admin { | |
| 25 | 32 | /** |
| 26 | 33 | * Instance of WP_User_Query. |
| 27 | 34 | * |
| 28 | 35 | * @var $user_search |
| @@ -55,18 +62,21 @@ | ||
| 55 | 62 | add_action( 'user_new_form', array( $this, 'render_wpcom_external_user_checkbox' ), 1 ); |
| 56 | 63 | add_action( 'user_new_form', array( $this, 'render_custom_email_message_form_field' ), 1 ); |
| 57 | 64 | add_action( 'delete_user_form', array( $this, 'render_invitations_notices_for_deleted_users' ) ); |
| 58 | 65 | add_action( 'delete_user', array( $this, 'revoke_user_invite' ) ); |
| 59 | - add_filter( 'manage_users_columns', array( $this, 'jetpack_user_connected_th' ) ); | |
| 60 | 66 | add_filter( 'manage_users_custom_column', array( $this, 'jetpack_show_connection_status' ), 10, 3 ); |
| 61 | 67 | add_action( 'user_row_actions', array( $this, 'jetpack_user_table_row_actions' ), 10, 2 ); |
| 62 | - add_action( 'admin_notices', array( $this, 'handle_invitation_results' ) ); | |
| 68 | + | |
| 69 | + if ( isset( $_GET['jetpack-sso-invite-user'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended | |
| 70 | + add_action( 'admin_notices', array( $this, 'handle_invitation_results' ) ); | |
| 71 | + } | |
| 72 | + | |
| 63 | 73 | add_action( 'admin_post_jetpack_invite_user_to_wpcom', array( $this, 'invite_user_to_wpcom' ) ); |
| 64 | 74 | add_action( 'admin_post_jetpack_revoke_invite_user_to_wpcom', array( $this, 'handle_request_revoke_invite' ) ); |
| 65 | 75 | add_action( 'admin_post_jetpack_resend_invite_user_to_wpcom', array( $this, 'handle_request_resend_invite' ) ); |
| 66 | - add_action( 'admin_print_styles-users.php', array( $this, 'jetpack_user_table_styles' ) ); | |
| 67 | 76 | add_filter( 'users_list_table_query_args', array( $this, 'set_user_query' ), 100, 1 ); |
| 68 | 77 | add_action( 'admin_print_styles-user-new.php', array( $this, 'jetpack_new_users_styles' ) ); |
| 78 | + add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); | |
| 69 | 79 | |
| 70 | 80 | self::$tracking = new Tracking(); |
| 71 | 81 | } |
| 72 | 82 | |
| @@ -101,8 +111,9 @@ | ||
| 101 | 111 | /** |
| 102 | 112 | * Revokes WordPress.com invitation. |
| 103 | 113 | * |
| 104 | 114 | * @param int $user_id The user ID. |
| 115 | + * @return mixed Response from the API call or false on failure. | |
| 105 | 116 | */ |
| 106 | 117 | public function revoke_user_invite( $user_id ) { |
| 107 | 118 | try { |
| 108 | 119 | $has_pending_invite = self::has_pending_wpcom_invite( $user_id ); |
| @@ -782,9 +793,9 @@ | ||
| 782 | 793 | name="user_external_contractor" |
| 783 | 794 | type="checkbox" |
| 784 | 795 | id="user_external_contractor" |
| 785 | 796 | > |
| 786 | - <?php esc_html_e( 'This user is a contractor, freelancer, consultant, or agency.', 'jetpack-connection' ); ?> | |
| 797 | + <?php esc_html_e( 'Mark as external collaborator', 'jetpack-connection' ); ?> | |
| 787 | 798 | </label> |
| 788 | 799 | </fieldset> |
| 789 | 800 | </td> |
| 790 | 801 | </tr> |
| @@ -969,45 +980,8 @@ | ||
| 969 | 980 | return $errors; |
| 970 | 981 | } |
| 971 | 982 | |
| 972 | 983 | /** |
| 973 | - * Adds a column in the user admin table to display user connection status and actions. | |
| 974 | - * | |
| 975 | - * @param array $columns User list table columns. | |
| 976 | - * | |
| 977 | - * @return array | |
| 978 | - */ | |
| 979 | - public function jetpack_user_connected_th( $columns ) { | |
| 980 | - Assets::register_script( | |
| 981 | - 'jetpack-sso-users', | |
| 982 | - '../../dist/jetpack-sso-users.js', | |
| 983 | - __FILE__, | |
| 984 | - array( | |
| 985 | - 'strategy' => 'defer', | |
| 986 | - 'in_footer' => true, | |
| 987 | - 'enqueue' => true, | |
| 988 | - 'version' => Package_Version::PACKAGE_VERSION, | |
| 989 | - ) | |
| 990 | - ); | |
| 991 | - | |
| 992 | - $tooltip_string = esc_attr__( 'Jetpack SSO allows a seamless and secure experience on WordPress.com. Join millions of WordPress users who trust us to keep their accounts safe.', 'jetpack-connection' ); | |
| 993 | - | |
| 994 | - wp_add_inline_script( | |
| 995 | - 'jetpack-sso-users', | |
| 996 | - "var Jetpack_SSOTooltip = { 'tooltipString': '{$tooltip_string}' }", | |
| 997 | - 'before' | |
| 998 | - ); | |
| 999 | - | |
| 1000 | - $columns['user_jetpack'] = sprintf( | |
| 1001 | - '<span class="jetpack-sso-invitation-tooltip-icon jetpack-sso-status-column" role="tooltip" aria-label="%3$s: %1$s" tabindex="0">%2$s</span>', | |
| 1002 | - $tooltip_string, | |
| 1003 | - esc_html__( 'SSO Status', 'jetpack-connection' ), | |
| 1004 | - esc_attr__( 'Tooltip', 'jetpack-connection' ) | |
| 1005 | - ); | |
| 1006 | - return $columns; | |
| 1007 | - } | |
| 1008 | - | |
| 1009 | - /** | |
| 1010 | 984 | * Executed when our WP_User_Query instance is set, and we don't have cached invites. |
| 1011 | 985 | * This function uses the user emails and the 'are-users-invited' endpoint to build the cache. |
| 1012 | 986 | * |
| 1013 | 987 | * @return void |
| @@ -1097,10 +1071,14 @@ | ||
| 1097 | 1071 | * |
| 1098 | 1072 | * @return false|string returns the user invite code if the user is invited, false otherwise. |
| 1099 | 1073 | */ |
| 1100 | 1074 | private static function has_pending_wpcom_invite( $user_id ) { |
| 1075 | + $user = get_user_by( 'id', $user_id ); | |
| 1076 | + if ( ! $user instanceof \WP_User ) { | |
| 1077 | + return false; | |
| 1078 | + } | |
| 1079 | + | |
| 1101 | 1080 | $blog_id = Manager::get_site_id( true ); |
| 1102 | - $user = get_user_by( 'id', $user_id ); | |
| 1103 | 1081 | $cached_invite = self::get_pending_cached_wpcom_invite( $user->user_email ); |
| 1104 | 1082 | |
| 1105 | 1083 | if ( $cached_invite ) { |
| 1106 | 1084 | return $cached_invite['invite_code']; |
| @@ -1174,55 +1152,53 @@ | ||
| 1174 | 1152 | * |
| 1175 | 1153 | * @param string $val HTML for the column. |
| 1176 | 1154 | * @param string $col User list table column. |
| 1177 | 1155 | * @param int $user_id User ID. |
| 1178 | - * | |
| 1179 | - * @return string | |
| 1156 | + * @return string Modified column content. | |
| 1180 | 1157 | */ |
| 1181 | 1158 | public function jetpack_show_connection_status( $val, $col, $user_id ) { |
| 1182 | - if ( 'user_jetpack' === $col ) { | |
| 1183 | - if ( ( new Manager() )->is_user_connected( $user_id ) ) { | |
| 1184 | - $connection_html = sprintf( | |
| 1185 | - '<span title="%1$s" class="jetpack-sso-invitation">%2$s</span>', | |
| 1186 | - esc_attr__( 'This user is connected and can log-in to this site.', 'jetpack-connection' ), | |
| 1187 | - esc_html__( 'Connected', 'jetpack-connection' ) | |
| 1159 | + if ( 'user_jetpack' !== $col ) { | |
| 1160 | + return $val; | |
| 1161 | + } | |
| 1162 | + | |
| 1163 | + // Get base connection status from parent | |
| 1164 | + $connection_status = parent::render_connection_column( '', $col, $user_id ); | |
| 1165 | + | |
| 1166 | + // If user is not connected, check for pending invite | |
| 1167 | + if ( ! $connection_status ) { | |
| 1168 | + $has_pending_invite = self::has_pending_wpcom_invite( $user_id ); | |
| 1169 | + if ( $has_pending_invite ) { | |
| 1170 | + return sprintf( | |
| 1171 | + '<span title="%1$s" class="jetpack-sso-invitation sso-pending-invite">%2$s</span>', | |
| 1172 | + esc_attr__( 'This user didn’t accept the invitation to join this site yet.', 'jetpack-connection' ), | |
| 1173 | + esc_html__( 'Pending invite', 'jetpack-connection' ) | |
| 1188 | 1174 | ); |
| 1189 | - return $connection_html; | |
| 1190 | - } else { | |
| 1191 | - $has_pending_invite = self::has_pending_wpcom_invite( $user_id ); | |
| 1192 | - if ( $has_pending_invite ) { | |
| 1193 | - $connection_html = sprintf( | |
| 1194 | - '<span title="%1$s" class="jetpack-sso-invitation sso-pending-invite">%2$s</span>', | |
| 1195 | - esc_attr__( 'This user didn’t accept the invitation to join this site yet.', 'jetpack-connection' ), | |
| 1196 | - esc_html__( 'Pending invite', 'jetpack-connection' ) | |
| 1197 | - ); | |
| 1198 | - return $connection_html; | |
| 1199 | - } | |
| 1200 | - $nonce = wp_create_nonce( 'jetpack-sso-invite-user' ); | |
| 1201 | - $connection_html = sprintf( | |
| 1202 | - // Using formmethod and formaction because we can't nest forms and have to submit using the main form. | |
| 1203 | - '<span tabindex="0" role="tooltip" aria-label="%4$s: %3$s" class="jetpack-sso-invitation-tooltip-icon sso-disconnected-user"> | |
| 1204 | - <a href="%1$s" class="jetpack-sso-invitation sso-disconnected-user">%2$s</a> | |
| 1205 | - <span class="sso-disconnected-user-icon dashicons dashicons-warning"> | |
| 1206 | - <span class="jetpack-sso-invitation-tooltip jetpack-sso-td-tooltip">%3$s</span> | |
| 1207 | - </span> | |
| 1208 | - </span>', | |
| 1209 | - add_query_arg( | |
| 1210 | - array( | |
| 1211 | - 'user_id' => $user_id, | |
| 1212 | - 'invite_nonce' => $nonce, | |
| 1213 | - 'action' => 'jetpack_invite_user_to_wpcom', | |
| 1214 | - ), | |
| 1215 | - admin_url( 'admin-post.php' ) | |
| 1175 | + } | |
| 1176 | + | |
| 1177 | + // Show invite button for non-connected users | |
| 1178 | + $nonce = wp_create_nonce( 'jetpack-sso-invite-user' ); | |
| 1179 | + return sprintf( | |
| 1180 | + '<span tabindex="0" role="tooltip" aria-label="%4$s: %3$s" class="jetpack-sso-invitation-tooltip-icon sso-disconnected-user"> | |
| 1181 | + <span class="sso-disconnected-user-icon dashicons dashicons-warning"> | |
| 1182 | + <span class="jetpack-sso-invitation-tooltip jetpack-sso-td-tooltip">%3$s</span> | |
| 1183 | + </span> | |
| 1184 | + <a href="%1$s" class="jetpack-sso-invitation sso-disconnected-user">%2$s</a> | |
| 1185 | + </span>', | |
| 1186 | + add_query_arg( | |
| 1187 | + array( | |
| 1188 | + 'user_id' => $user_id, | |
| 1189 | + 'invite_nonce' => $nonce, | |
| 1190 | + 'action' => 'jetpack_invite_user_to_wpcom', | |
| 1216 | 1191 | ), |
| 1217 | - esc_html__( 'Send invite', 'jetpack-connection' ), | |
| 1218 | - esc_attr__( 'This user doesn’t have an SSO connection to WordPress.com. Invite them to the site to increase security and improve their experience.', 'jetpack-connection' ), | |
| 1219 | - esc_attr__( 'Tooltip', 'jetpack-connection' ) | |
| 1220 | - ); | |
| 1221 | - return $connection_html; | |
| 1222 | - } | |
| 1192 | + admin_url( 'admin-post.php' ) | |
| 1193 | + ), | |
| 1194 | + esc_html__( 'Send invite', 'jetpack-connection' ), | |
| 1195 | + esc_attr__( 'This user doesn’t have a Jetpack SSO connection to WordPress.com. Invite them to the site to increase security and improve their experience.', 'jetpack-connection' ), | |
| 1196 | + esc_attr__( 'Tooltip', 'jetpack-connection' ) | |
| 1197 | + ); | |
| 1223 | 1198 | } |
| 1224 | - return $val; | |
| 1199 | + | |
| 1200 | + return $connection_status; | |
| 1225 | 1201 | } |
| 1226 | 1202 | |
| 1227 | 1203 | /** |
| 1228 | 1204 | * Creates error notices and redirects the user to the previous page. |
| @@ -1227,8 +1203,9 @@ | ||
| 1227 | 1203 | /** |
| 1228 | 1204 | * Creates error notices and redirects the user to the previous page. |
| 1229 | 1205 | * |
| 1230 | 1206 | * @param array $query_params - query parameters added to redirection URL. |
| 1207 | + * @phan-suppress PhanPluginNeverReturnMethod | |
| 1231 | 1208 | */ |
| 1232 | 1209 | public function create_error_notice_and_redirect( $query_params ) { |
| 1233 | 1210 | $ref = wp_get_referer(); |
| 1234 | 1211 | if ( empty( $ref ) ) { |
| @@ -1238,85 +1215,122 @@ | ||
| 1238 | 1215 | $url = add_query_arg( |
| 1239 | 1216 | $query_params, |
| 1240 | 1217 | $ref |
| 1241 | 1218 | ); |
| 1242 | - return wp_safe_redirect( $url ); | |
| 1219 | + wp_safe_redirect( $url ); | |
| 1220 | + exit; | |
| 1243 | 1221 | } |
| 1244 | 1222 | |
| 1245 | 1223 | /** |
| 1246 | - * Style the Jetpack user rows and columns. | |
| 1224 | + * Enqueue the styles for the Jetpack user rows and columns. | |
| 1247 | 1225 | */ |
| 1248 | 1226 | public function jetpack_user_table_styles() { |
| 1249 | - ?> | |
| 1250 | - <style> | |
| 1251 | - #the-list tr:has(.sso-disconnected-user) { | |
| 1252 | - background: #F5F1E1; | |
| 1227 | + $handle = 'jetpack-sso-users-styles'; | |
| 1228 | + | |
| 1229 | + // No src: the handle only carries the inline CSS below. | |
| 1230 | + wp_register_style( $handle, false, array(), Package_Version::PACKAGE_VERSION ); | |
| 1231 | + wp_enqueue_style( $handle ); | |
| 1232 | + | |
| 1233 | + $css = <<<'CSS' | |
| 1234 | +#the-list tr:has(.sso-disconnected-user) { | |
| 1235 | + background: #F5F1E1; | |
| 1236 | +} | |
| 1237 | + | |
| 1238 | +#the-list tr:has(.sso-pending-invite) { | |
| 1239 | + background: #E9F0F5; | |
| 1240 | +} | |
| 1241 | + | |
| 1242 | +.jetpack-sso-invitation { | |
| 1243 | + background: none; | |
| 1244 | + border: none; | |
| 1245 | + color: #50575e; | |
| 1246 | + padding: 0; | |
| 1247 | + text-align: unset; | |
| 1248 | +} | |
| 1249 | + | |
| 1250 | +.jetpack-sso-invitation.sso-disconnected-user { | |
| 1251 | + color: #0073aa; | |
| 1252 | + cursor: pointer; | |
| 1253 | + text-decoration: underline; | |
| 1254 | +} | |
| 1255 | + | |
| 1256 | +.jetpack-sso-invitation.sso-disconnected-user:hover, | |
| 1257 | +.jetpack-sso-invitation.sso-disconnected-user:focus, | |
| 1258 | +.jetpack-sso-invitation.sso-disconnected-user:active { | |
| 1259 | + color: #0096dd; | |
| 1260 | +} | |
| 1261 | + | |
| 1262 | +.sso-disconnected-user-icon { | |
| 1263 | + cursor: pointer; | |
| 1264 | + background: gray; | |
| 1265 | + border-radius: 10px; | |
| 1266 | +} | |
| 1267 | + | |
| 1268 | +.sso-disconnected-user-icon.dashicons { | |
| 1269 | + font-size: 1rem; | |
| 1270 | + height: 1rem; | |
| 1271 | + width: 1rem; | |
| 1272 | + background-color: #9D6E00; | |
| 1273 | + color: #F5F1E1; | |
| 1274 | +} | |
| 1275 | + | |
| 1276 | +.jetpack-sso-invitation-tooltip-icon { | |
| 1277 | + position: relative; | |
| 1278 | + cursor: pointer; | |
| 1279 | + display: inline-flex; | |
| 1280 | + align-items: center; | |
| 1281 | + column-gap: 6px; | |
| 1282 | +} | |
| 1283 | + | |
| 1284 | +.jetpack-sso-td-tooltip { | |
| 1285 | + left: -256px; | |
| 1286 | +} | |
| 1287 | + | |
| 1288 | +.jetpack-sso-invitation-tooltip { | |
| 1289 | + position: absolute; | |
| 1290 | + background: #f6f7f7; | |
| 1291 | + top: -85px; | |
| 1292 | + width: 250px; | |
| 1293 | + padding: 7px; | |
| 1294 | + color: #3c434a; | |
| 1295 | + font-size: .75rem; | |
| 1296 | + line-height: 17px; | |
| 1297 | + text-align: left; | |
| 1298 | + margin: 0; | |
| 1299 | + display: none; | |
| 1300 | + border-radius: 4px; | |
| 1301 | + font-family: sans-serif; | |
| 1302 | + box-shadow: 5px 10px 10px rgba(0, 0, 0, 0.1); | |
| 1303 | +} | |
| 1304 | +CSS; | |
| 1305 | + | |
| 1306 | + wp_add_inline_style( $handle, $css ); | |
| 1307 | + } | |
| 1308 | + | |
| 1309 | + /** | |
| 1310 | + * Enqueue SSO-specific scripts. | |
| 1311 | + * | |
| 1312 | + * @param string $hook The current admin page. | |
| 1313 | + */ | |
| 1314 | + public function enqueue_scripts( $hook ) { | |
| 1315 | + if ( 'users.php' !== $hook ) { | |
| 1316 | + return; | |
| 1253 | 1317 | } |
| 1254 | - #the-list tr:has(.sso-pending-invite) { | |
| 1255 | - background: #E9F0F5; | |
| 1256 | - } | |
| 1257 | - .fixed .column-user_jetpack { | |
| 1258 | - width: 100px; | |
| 1259 | - } | |
| 1260 | - .jetpack-sso-invitation { | |
| 1261 | - background: none; | |
| 1262 | - border: none; | |
| 1263 | - color: #50575e; | |
| 1264 | - padding: 0; | |
| 1265 | - text-align: unset; | |
| 1266 | - } | |
| 1267 | - .jetpack-sso-invitation.sso-disconnected-user { | |
| 1268 | - color: #0073aa; | |
| 1269 | - cursor: pointer; | |
| 1270 | - text-decoration: underline; | |
| 1271 | - } | |
| 1272 | - .jetpack-sso-invitation.sso-disconnected-user:hover, | |
| 1273 | - .jetpack-sso-invitation.sso-disconnected-user:focus, | |
| 1274 | - .jetpack-sso-invitation.sso-disconnected-user:active { | |
| 1275 | - color: #0096dd; | |
| 1276 | - } | |
| 1277 | 1318 | |
| 1278 | - .sso-disconnected-user-icon { | |
| 1279 | - margin-left: 4px; | |
| 1280 | - cursor: pointer; | |
| 1281 | - background: gray; | |
| 1282 | - border-radius: 10px; | |
| 1283 | - } | |
| 1319 | + parent::enqueue_scripts( $hook ); | |
| 1284 | 1320 | |
| 1285 | - .sso-disconnected-user-icon.dashicons { | |
| 1286 | - font-size: 1rem; | |
| 1287 | - height: 1rem; | |
| 1288 | - width: 1rem; | |
| 1289 | - background-color: #9D6E00; | |
| 1290 | - color: #F5F1E1; | |
| 1291 | - } | |
| 1292 | - .jetpack-sso-invitation-tooltip-icon{ | |
| 1293 | - position: relative; | |
| 1294 | - cursor: pointer; | |
| 1295 | - } | |
| 1296 | - .jetpack-sso-th-tooltip { | |
| 1297 | - left: -170px; | |
| 1298 | - } | |
| 1299 | - .jetpack-sso-td-tooltip { | |
| 1300 | - left: -256px; | |
| 1301 | - } | |
| 1302 | - .jetpack-sso-invitation-tooltip { | |
| 1303 | - position: absolute; | |
| 1304 | - background: #f6f7f7; | |
| 1305 | - top: -85px; | |
| 1306 | - width: 250px; | |
| 1307 | - padding: 7px; | |
| 1308 | - color: #3c434a; | |
| 1309 | - font-size: .75rem; | |
| 1310 | - line-height: 17px; | |
| 1311 | - text-align: left; | |
| 1312 | - margin: 0; | |
| 1313 | - display: none; | |
| 1314 | - border-radius: 4px; | |
| 1315 | - font-family: sans-serif; | |
| 1316 | - box-shadow: 5px 10px 10px rgba(0, 0, 0, 0.1); | |
| 1317 | - } | |
| 1321 | + $this->jetpack_user_table_styles(); | |
| 1318 | 1322 | |
| 1319 | - </style> | |
| 1320 | - <?php | |
| 1323 | + // Enqueue the SSO users script. | |
| 1324 | + Assets::register_script( | |
| 1325 | + 'jetpack-sso-users', | |
| 1326 | + '../../dist/jetpack-sso-users.js', | |
| 1327 | + __FILE__, | |
| 1328 | + array( | |
| 1329 | + 'strategy' => 'defer', | |
| 1330 | + 'in_footer' => true, | |
| 1331 | + 'enqueue' => true, | |
| 1332 | + 'version' => Package_Version::PACKAGE_VERSION, | |
| 1333 | + ) | |
| 1334 | + ); | |
| 1321 | 1335 | } |
| 1322 | 1336 | } |