fix(identity): complete native certification review flow

This commit is contained in:
kate522 committed 2026-07-29 12:25:58 +08:00
1 parent 32658be87d
commit 2dfaa10798
16 files changed
+571 -1167

No files matched your search

@@ -9,311 +9,6 @@ defined('ABSPATH') || exit;
trait UserControllerVerifyIntegrations {
public function get_verify_pending(): \WP_REST_Response {
$response = $this->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);
}
$current_status = sanitize_key((string) get_user_meta($user_id, 'aksrt_user_verify_status', true));
$application = get_user_meta($user_id, 'aksrt_user_verify_apply', true);
if ($current_status !== 'pending' || !is_array($application) || empty($application['name']) || empty($application['type'])) {
return $this->error(__('该用户没有可审核的认证申请', 'aksrt'), 409);
}
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');
}
if ($status === 'verified') {
$apply = get_user_meta($user_id, 'aksrt_user_verify_apply', true);
if (is_array($apply)) {
update_user_meta($user_id, 'aksrt_user_verify_info', [
'name' => (string) ($apply['name'] ?? ''),
'desc' => (string) ($apply['desc'] ?? ''),
'type' => (string) ($apply['type'] ?? ''),
'time' => current_time('Y-m-d H:i'),
]);
}
}
$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);
if (class_exists('\AKSRT\Messages\Message')) {
$message = $status === 'verified'
? __('您的官方认证申请已通过审核', 'aksrt')
: sprintf(__('您的官方认证申请未通过:%s', 'aksrt'), $note !== '' ? $note : __('请修改资料后重新申请', 'aksrt'));
\AKSRT\Messages\Message::get_instance()->send($user_id, 'auth_apply_reply', $message, [
'title' => __('官方认证审核结果', 'aksrt'),
'target_url' => aksrt_get_user_center_tab_url('auth'),
]);
}
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);
$application = get_user_meta($user_id, 'aksrt_user_verify_apply', true);
$application = is_array($application) ? $application : [];
$application_view = class_exists('\AKSRT\User\AuthApply')
? \AKSRT\User\AuthApply::application_view($application)
: [];
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) ($application['time'] ?? $row['user_registered'] ?? ''),
'reviewed_at' => (string) ($row['reviewed_at'] ?? ''),
'email_verified' => $email_verified,
'application' => $application_view,
'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.
*/