get_verify_requests(new WP_REST_Request('GET', '/')); $data = $response->get_data(); $items = isset($data['data']['items']) && is_array($data['data']['items']) ? $data['data']['items'] : []; $pending = array_values(array_filter($items, static function ($item) { return ($item['status'] ?? '') === 'pending'; })); return $this->success([ 'data' => [ 'requests' => array_slice($pending, 0, 50), 'total' => count($pending), ], ]); } public function get_verify_requests(WP_REST_Request $request): WP_REST_Response { global $wpdb; $page = max(1, (int) ($request->get_param('page') ?: 1)); $per_page = max(1, min(100, (int) ($request->get_param('per_page') ?: 20))); $keyword = trim(sanitize_text_field((string) $request->get_param('keyword'))); $status = sanitize_key((string) $request->get_param('status')); $date_from = sanitize_text_field((string) $request->get_param('date_from')); $date_to = sanitize_text_field((string) $request->get_param('date_to')); $sql = " SELECT u.ID, u.display_name, u.user_email, u.user_registered, status.meta_value AS verify_status, reason.meta_value AS verify_reason, reviewed_at.meta_value AS reviewed_at, reviewer.meta_value AS reviewer_id FROM {$wpdb->users} u INNER JOIN {$wpdb->usermeta} status ON status.user_id = u.ID AND status.meta_key = 'aksrt_user_verify_status' LEFT JOIN {$wpdb->usermeta} reason ON reason.user_id = u.ID AND reason.meta_key = 'aksrt_user_verify_reason' LEFT JOIN {$wpdb->usermeta} reviewed_at ON reviewed_at.user_id = u.ID AND reviewed_at.meta_key = 'aksrt_user_verify_reviewed_at' LEFT JOIN {$wpdb->usermeta} reviewer ON reviewer.user_id = u.ID AND reviewer.meta_key = 'aksrt_user_verify_reviewer' ORDER BY u.user_registered DESC LIMIT 500 "; $rows = $wpdb->get_results($sql, ARRAY_A); $items = []; $counts = ['pending' => 0, 'verified' => 0, 'rejected' => 0, 'total' => 0]; foreach ((array) $rows as $row) { $item = $this->build_verify_request_item($row); $item_status = $item['status']; if (isset($counts[$item_status])) { $counts[$item_status]++; } $counts['total']++; if ($status !== '' && $item_status !== $status) { continue; } if ($date_from !== '' && strcmp((string) $item['requested_at'], $date_from . ' 00:00:00') < 0) { continue; } if ($date_to !== '' && strcmp((string) $item['requested_at'], $date_to . ' 23:59:59') > 0) { continue; } if ($keyword !== '' && mb_stripos(implode(' ', [ (string) ($item['display_name'] ?? ''), (string) ($item['email'] ?? ''), (string) ($item['reason'] ?? ''), ]), $keyword) === false) { continue; } $items[] = $item; } $total = count($items); $offset = ($page - 1) * $per_page; return $this->success([ 'data' => [ 'items' => array_values(array_slice($items, $offset, $per_page)), 'total' => $total, 'page' => $page, 'per_page' => $per_page, 'counts' => $counts, 'options' => [ 'statuses' => [ ['label' => __('待审核', 'aksrt'), 'value' => 'pending'], ['label' => __('已通过', 'aksrt'), 'value' => 'verified'], ['label' => __('已驳回', 'aksrt'), 'value' => 'rejected'], ], ], ], ]); } public function get_verify_request_detail(WP_REST_Request $request): WP_REST_Response { $user_id = (int) $request->get_param('id'); if ($user_id <= 0) { return $this->error(__('认证申请不存在', 'aksrt'), 404); } $user = get_userdata($user_id); if (!$user) { return $this->error(__('用户不存在', 'aksrt'), 404); } $detail = $this->build_verify_request_item([ 'ID' => $user->ID, 'display_name' => $user->display_name, 'user_email' => $user->user_email, 'user_registered' => $user->user_registered, 'verify_status' => get_user_meta($user_id, 'aksrt_user_verify_status', true), 'verify_reason' => get_user_meta($user_id, 'aksrt_user_verify_reason', true), 'reviewed_at' => get_user_meta($user_id, 'aksrt_user_verify_reviewed_at', true), 'reviewer_id' => get_user_meta($user_id, 'aksrt_user_verify_reviewer', true), ]); return $this->success([ 'data' => [ 'request' => $detail, 'history' => $this->get_verify_history_for_user($user_id), 'options' => [ 'statuses' => [ ['label' => __('通过认证', 'aksrt'), 'value' => 'verified'], ['label' => __('驳回申请', 'aksrt'), 'value' => 'rejected'], ], ], ], ]); } /** * POST /verify/review — approve or reject a verification request. */ public function review_verify_request(WP_REST_Request $request): WP_REST_Response { $params = $this->get_json_params($request); $user_id = (int) ($params['user_id'] ?? 0); if ($user_id <= 0) { return $this->error(__('参数无效', 'aksrt')); } return $this->perform_verify_review($user_id, $params); } public function review_verify_request_by_id(WP_REST_Request $request): WP_REST_Response { $user_id = (int) $request->get_param('id'); if ($user_id <= 0) { return $this->error(__('参数无效', 'aksrt')); } return $this->perform_verify_review($user_id, $this->get_json_params($request)); } private function perform_verify_review(int $user_id, array $payload): WP_REST_Response { $status = sanitize_key((string) ($payload['status'] ?? '')); $note = sanitize_textarea_field((string) ($payload['note'] ?? ($payload['reason'] ?? ''))); if (!in_array($status, ['verified', 'rejected'], true)) { return $this->error(__('审核状态无效', 'aksrt')); } $user = get_userdata($user_id); if (!$user) { return $this->error(__('用户不存在', 'aksrt'), 404); } update_user_meta($user_id, 'aksrt_user_verify_status', $status); update_user_meta($user_id, 'aksrt_user_verify_reviewed_at', current_time('mysql')); update_user_meta($user_id, 'aksrt_user_verify_reviewer', get_current_user_id()); if ($note !== '') { update_user_meta($user_id, 'aksrt_user_verify_reason', $note); } elseif ($status === 'verified') { delete_user_meta($user_id, 'aksrt_user_verify_reason'); } $log = get_option('aksrt_verify_review_log', []); if (!is_array($log)) { $log = []; } $log[] = [ 'user_id' => $user_id, 'reviewer' => get_current_user_id(), 'status' => $status, 'reason' => $note, 'time' => current_time('mysql'), ]; if (count($log) > 500) { $log = array_slice($log, -500); } update_option('aksrt_verify_review_log', $log, false); return $this->success([ 'message' => $status === 'verified' ? __('已通过认证', 'aksrt') : __('已驳回申请', 'aksrt'), ]); } private function build_verify_request_item(array $row): array { $user_id = (int) ($row['ID'] ?? 0); $reviewer_id = (int) ($row['reviewer_id'] ?? 0); $reviewer = $reviewer_id > 0 ? get_userdata($reviewer_id) : null; $status = sanitize_key((string) ($row['verify_status'] ?? 'pending')); $email_verified = (bool) get_user_meta($user_id, 'aksrt_email_verified', true); return [ 'user_id' => $user_id, 'display_name' => (string) ($row['display_name'] ?? ''), 'email' => (string) ($row['user_email'] ?? ''), 'status' => $status, 'reason' => (string) ($row['verify_reason'] ?? ''), 'requested_at' => (string) ($row['user_registered'] ?? ''), 'reviewed_at' => (string) ($row['reviewed_at'] ?? ''), 'email_verified' => $email_verified, 'reviewer' => $this->build_admin_user_summary($reviewer_id, $reviewer), 'history_count' => count($this->get_verify_history_for_user($user_id)), ]; } private function get_verify_history_for_user(int $user_id): array { $log = get_option('aksrt_verify_review_log', []); if (!is_array($log)) { return []; } $history = []; foreach ($log as $entry) { if ((int) ($entry['user_id'] ?? 0) !== $user_id) { continue; } $reviewer_id = (int) ($entry['reviewer'] ?? 0); $history[] = [ 'status' => sanitize_key((string) ($entry['status'] ?? '')), 'reason' => (string) ($entry['reason'] ?? ''), 'time' => (string) ($entry['time'] ?? ''), 'reviewer' => $reviewer_id, 'reviewer_name' => $reviewer_id > 0 && ($user = get_userdata($reviewer_id)) ? $user->display_name : '', ]; } usort($history, static function ($left, $right) { return strcmp((string) ($right['time'] ?? ''), (string) ($left['time'] ?? '')); }); return $history; } private function build_admin_user_summary(int $user_id, $user = null): ?array { if ($user_id <= 0 && !$user instanceof WP_User) { return null; } if (!$user instanceof WP_User) { $user = get_userdata($user_id); } if (!$user instanceof WP_User) { return null; } return [ 'id' => (int) $user->ID, 'display_name' => (string) $user->display_name, 'email' => (string) $user->user_email, 'avatar_url' => get_avatar_url((int) $user->ID, ['size' => 64]), ]; } /** * GET /sms/status — SMS provider connection status. */ public function get_sms_status(): WP_REST_Response { if (class_exists('AKSRT_SMS')) { return $this->success(['data' => AKSRT_SMS::get_instance()->get_provider_status()]); } return $this->success([ 'data' => [ 'enabled' => false, 'provider' => 'none', 'configured' => false, 'available' => false, 'verified' => false, 'transport' => '', 'missing_fields' => [], 'code_length' => 6, 'code_expire' => 300, 'rate_limit' => 60, 'daily_limit' => 10, 'notify_bind' => true, 'notify_login' => false, ], ]); } /** * POST /sms/test — Send a test SMS to verify provider configuration. */ public function test_sms_send(WP_REST_Request $request): WP_REST_Response { if (!class_exists('AKSRT_SMS')) { return $this->error('短信服务不可用'); } $params = $this->get_json_params($request); $phone = sanitize_text_field((string) ($params['phone'] ?? '')); if (!preg_match('/^1[3-9]\d{9}$/', $phone)) { return $this->error('手机号格式不正确'); } $result = AKSRT_SMS::get_instance()->test_provider($phone); if (!empty($result['success'])) { return $this->success(['message' => $result['message'] ?? '发送成功']); } return $this->error($result['message'] ?? '发送失败'); } /** * GET /wechat/status — WeChat notification service status. */ public function get_wechat_status(): WP_REST_Response { if (class_exists('AKSRT_WeChat_Notify')) { return $this->success(['data' => AKSRT_WeChat_Notify::get_instance()->get_status()]); } return $this->success([ 'data' => [ 'appid' => '', 'configured' => false, 'has_token' => false, 'available' => false, ], ]); } /** * POST /wechat/settings — 更新微信通知设置 */ public function update_wechat_settings(WP_REST_Request $request): WP_REST_Response { $params = $this->get_json_params($request); $settings = [ 'enabled' => !empty($params['enabled']), 'app_id' => sanitize_text_field((string) ($params['app_id'] ?? '')), 'app_secret' => sanitize_text_field((string) ($params['app_secret'] ?? '')), 'template_id' => sanitize_text_field((string) ($params['template_id'] ?? '')), ]; $existing = AKSRT_Settings::get_wechat_settings(); if ($settings['app_secret'] === '***') { $settings['app_secret'] = $existing['app_secret'] ?? ''; } $merged = array_merge($existing, $settings); AKSRT_Settings::update_wechat_settings($merged); delete_transient('aksrt_wechat_token'); return $this->success(['message' => __('微信设置已保存', 'aksrt')]); } }