] * : 限定單一 user 同步(預設全部) * * [--batch-size=] * : 每批處理筆數(預設 500) * * [--dry-run] * : 只顯示會做什麼,不實際寫入 * * @param array $args * @param array $assoc_args */ public static function sync( $args, $assoc_args ): void { $user_id = isset( $assoc_args['user-id'] ) ? absint( $assoc_args['user-id'] ) : 0; $batch = isset( $assoc_args['batch-size'] ) ? max( 1, absint( $assoc_args['batch-size'] ) ) : 500; $dry_run = ! empty( $assoc_args['dry-run'] ); if ( ! class_exists( 'TMDO_API' ) && ! class_exists( 'WPDO_API' ) ) { \WP_CLI::error( '需要 2meet-data-optimizer 核心啟用' ); } $api = class_exists( 'TMDO_API' ) ? 'TMDO_API' : 'WPDO_API'; global $wpdb; $where = $user_id ? $wpdb->prepare( 'AND user_id = %d', $user_id ) : ''; // 支援 _tmso_global_user_id / _tmso_picture_url / _tmso_refresh_token 三個舊 key $rows = $wpdb->get_results( "SELECT user_id, meta_key, meta_value FROM {$wpdb->usermeta} WHERE meta_key IN ('_tmso_global_user_id','_tmso_picture_url','_tmso_refresh_token') $where LIMIT $batch", ARRAY_A ); if ( empty( $rows ) ) { \WP_CLI::success( '無待同步資料' ); return; } $migrated = 0; $key_map = array( '_tmso_global_user_id' => 'hub_global_user_id', '_tmso_picture_url' => 'picture_url', '_tmso_refresh_token' => 'refresh_token_enc', ); foreach ( $rows as $row ) { $dst_key = $key_map[ $row['meta_key'] ] ?? null; if ( ! $dst_key ) { continue; } if ( $dry_run ) { \WP_CLI::log( "[dry-run] user={$row['user_id']} {$row['meta_key']} → {$dst_key}" ); } else { $api::set_entity( 'user', (int) $row['user_id'], $dst_key, $row['meta_value'] ); } $migrated++; } \WP_CLI::success( ( $dry_run ? '[dry-run] would migrate ' : 'migrated ' ) . $migrated . ' rows' ); } /** * 強制使用者 SSO token 過期(設 token_expires_at 為過去時間)。 * * ## OPTIONS * * [--user-id=] * : Local user ID * * [--global-user-id=] * : Hub global user UUID * * [--all] * : 強制全部 user 重認 * * [--dry-run] * : 只顯示會做什麼 * * @param array $args * @param array $assoc_args */ public static function force_logout( $args, $assoc_args ): void { if ( ! class_exists( 'TMDO_API' ) && ! class_exists( 'WPDO_API' ) ) { \WP_CLI::error( '需要 2meet-data-optimizer 核心啟用' ); } $api = class_exists( 'TMDO_API' ) ? 'TMDO_API' : 'WPDO_API'; $dry_run = ! empty( $assoc_args['dry-run'] ); $user_id = isset( $assoc_args['user-id'] ) ? absint( $assoc_args['user-id'] ) : 0; $global_uuid = isset( $assoc_args['global-user-id'] ) ? sanitize_text_field( $assoc_args['global-user-id'] ) : ''; $all = ! empty( $assoc_args['all'] ); if ( ! $user_id && ! $global_uuid && ! $all ) { \WP_CLI::error( '需指定 --user-id / --global-user-id / --all 其中之一' ); } global $wpdb; $past = '2000-01-01 00:00:00'; $ids = array(); if ( $user_id ) { $ids[] = $user_id; } elseif ( $global_uuid ) { $flat_table = $wpdb->prefix . 'wpdo_user_sso'; $id = $wpdb->get_var( $wpdb->prepare( "SELECT user_id FROM $flat_table WHERE hub_global_user_id = %s LIMIT 1", $global_uuid ) ); if ( $id ) { $ids[] = (int) $id; } } elseif ( $all ) { $flat_table = $wpdb->prefix . 'wpdo_user_sso'; $rows = $wpdb->get_col( "SELECT user_id FROM $flat_table" ); $ids = array_map( 'intval', $rows ); } if ( empty( $ids ) ) { \WP_CLI::warning( '找不到符合條件的 user' ); return; } foreach ( $ids as $uid ) { if ( $dry_run ) { \WP_CLI::log( "[dry-run] user={$uid} token_expires_at → {$past}" ); } else { $api::set_entity( 'user', $uid, 'token_expires_at', $past ); } } \WP_CLI::success( ( $dry_run ? '[dry-run] would force-logout ' : 'force-logout ' ) . count( $ids ) . ' users' ); } }