['GET', 'POST'], 'callback' => [$this, 'rest_handle_auth_settings'], 'permission_callback' => [$this, 'check_permission'], ]); // OAuth settings register_rest_route(self::API_NAMESPACE, '/settings/oauth', [ 'methods' => ['GET', 'POST'], 'callback' => [$this, 'rest_handle_oauth'], 'permission_callback' => [$this, 'check_permission'], ]); // OAuth proxy settings register_rest_route(self::API_NAMESPACE, '/settings/oauth-proxy', [ 'methods' => ['GET', 'POST'], 'callback' => [$this, 'rest_handle_oauth_proxy'], 'permission_callback' => [$this, 'check_permission'], ]); // User profile media uploads (logged-in users). register_rest_route(self::API_NAMESPACE, '/user/background', [ 'methods' => 'POST', 'callback' => [$this, 'rest_upload_user_background'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); register_rest_route(self::API_NAMESPACE, '/user/avatar', [ [ 'methods' => 'POST', 'callback' => [$this, 'rest_upload_user_avatar'], 'permission_callback' => function () { return is_user_logged_in(); }, ], [ 'methods' => 'DELETE', 'callback' => [$this, 'rest_delete_user_avatar'], 'permission_callback' => function () { return is_user_logged_in(); }, ], ]); // Comment inline image upload (logged-in users) register_rest_route(self::API_NAMESPACE, '/comment/upload-image', [ 'methods' => 'POST', 'callback' => [$this, 'rest_upload_comment_image'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); // Notification settings register_rest_route(self::API_NAMESPACE, '/settings/notifications', [ 'methods' => ['GET', 'POST'], 'callback' => [$this, 'rest_handle_notification_settings'], 'permission_callback' => [$this, 'check_permission'], ]); // Keep message-center aliases on this controller so existing admin pages // remain compatible while notifications runtime lives in Message controller. register_rest_route(self::API_NAMESPACE, '/notifications/overview', [ 'methods' => 'GET', 'callback' => [$this, 'rest_get_notification_overview'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/notifications/mark-read', [ 'methods' => 'POST', 'callback' => [$this, 'rest_mark_notification_read'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/notifications/(?P\d+)', [ 'methods' => 'DELETE', 'callback' => [$this, 'rest_delete_notification_item'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/notifications/cleanup', [ 'methods' => 'POST', 'callback' => [$this, 'rest_run_notification_cleanup'], 'permission_callback' => [$this, 'check_permission'], ]); // Mail templates (email content templates) register_rest_route(self::API_NAMESPACE, '/settings/mail-templates', [ 'methods' => ['GET', 'POST'], 'callback' => [$this, 'handle_mail_templates'], 'permission_callback' => [$this, 'check_permission'], ]); // Credits settings (admin) register_rest_route(self::API_NAMESPACE, '/credits/settings', [ 'methods' => ['GET', 'POST'], 'callback' => [$this, 'rest_handle_credit_settings'], 'permission_callback' => [$this, 'check_permission'], ]); // Credits — current user balance (frontend) register_rest_route(self::API_NAMESPACE, '/credits/me', [ 'methods' => 'GET', 'callback' => [$this, 'rest_get_credits_me'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); // Credits — user list (admin) register_rest_route(self::API_NAMESPACE, '/credits/users', [ 'methods' => 'GET', 'callback' => [$this, 'rest_list_credit_users'], 'permission_callback' => [$this, 'check_permission'], ]); // Credits — adjust user balance (admin) register_rest_route(self::API_NAMESPACE, '/credits/users/(?P\d+)/adjust', [ 'methods' => 'POST', 'callback' => [$this, 'rest_adjust_user_credits'], 'permission_callback' => [$this, 'check_permission'], ]); // Credits — transaction log (admin) register_rest_route(self::API_NAMESPACE, '/credits/log', [ 'methods' => 'GET', 'callback' => [$this, 'rest_get_credits_log'], 'permission_callback' => [$this, 'check_permission'], ]); // Report ticket list (admin) register_rest_route(self::API_NAMESPACE, '/report/list', [ 'methods' => 'GET', 'callback' => [$this, 'get_report_list'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/users/reports', [ 'methods' => 'GET', 'callback' => [$this, 'get_report_list'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/users/reports/(?P\d+)', [ 'methods' => 'GET', 'callback' => [$this, 'get_report_detail'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/users/reports/(?P\d+)/process', [ 'methods' => 'POST', 'callback' => [$this, 'process_report'], 'permission_callback' => [$this, 'check_permission'], ]); // Report status update (admin) register_rest_route(self::API_NAMESPACE, '/report/update-status', [ 'methods' => 'POST', 'callback' => [$this, 'update_report_status'], 'permission_callback' => [$this, 'check_permission'], ]); // Report counts (admin) register_rest_route(self::API_NAMESPACE, '/report/counts', [ 'methods' => 'GET', 'callback' => [$this, 'get_report_counts'], 'permission_callback' => [$this, 'check_permission'], ]); // Report submit (logged-in users, front-end) register_rest_route(self::API_NAMESPACE, '/report/submit', [ 'methods' => 'POST', 'callback' => [$this, 'submit_report'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); // Follow toggle (logged-in users) register_rest_route(self::API_NAMESPACE, '/follow/toggle', [ 'methods' => 'POST', 'callback' => [$this, 'follow_toggle'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); // Follow status check (logged-in users) register_rest_route(self::API_NAMESPACE, '/follow/status', [ 'methods' => 'GET', 'callback' => [$this, 'follow_status'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); // Follow counts (public) register_rest_route(self::API_NAMESPACE, '/follow/counts', [ 'methods' => 'GET', 'callback' => [$this, 'follow_counts'], 'permission_callback' => '__return_true', ]); // Invite codes management (admin) register_rest_route(self::API_NAMESPACE, '/invite/codes', [ 'methods' => 'GET', 'callback' => [$this, 'get_invite_codes'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/invite/codes', [ 'methods' => 'POST', 'callback' => [$this, 'generate_invite_codes'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/invite/codes/(?P\d+)/disable', [ 'methods' => 'POST', 'callback' => [$this, 'disable_invite_code'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/invite/codes/bulk', [ 'methods' => 'POST', 'callback' => [$this, 'bulk_update_invite_codes'], 'permission_callback' => [$this, 'check_permission'], ]); register_rest_route(self::API_NAMESPACE, '/invite/stats', [ 'methods' => 'GET', 'callback' => [$this, 'get_invite_stats'], 'permission_callback' => [$this, 'check_permission'], ]); // ── Modal Auth (弹窗登录/注册) ── // Modal login register_rest_route(self::API_NAMESPACE, '/auth/modal-login', [ 'methods' => 'POST', 'callback' => [$this, 'modal_login'], 'permission_callback' => '__return_true', ]); // Modal register register_rest_route(self::API_NAMESPACE, '/auth/modal-register', [ 'methods' => 'POST', 'callback' => [$this, 'modal_register'], 'permission_callback' => '__return_true', ]); // Current user info (for AJAX refresh) register_rest_route(self::API_NAMESPACE, '/auth/me', [ 'methods' => 'GET', 'callback' => [$this, 'get_current_user_info'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); // Identity verification provider settings (admin only) register_rest_route(self::API_NAMESPACE, '/identity/settings', [ [ 'methods' => 'GET', 'callback' => [$this, 'get_identity_settings'], 'permission_callback' => [$this, 'check_permission'], ], [ 'methods' => 'POST', 'callback' => [$this, 'update_identity_settings'], 'permission_callback' => [$this, 'check_permission'], ], ]); register_rest_route(self::API_NAMESPACE, '/identity/settings/test', [ 'methods' => 'POST', 'callback' => [$this, 'test_identity_settings'], 'permission_callback' => [$this, 'check_permission'], ]); // SMS provider status register_rest_route(self::API_NAMESPACE, '/sms/status', [ 'methods' => 'GET', 'callback' => [$this, 'get_sms_status'], 'permission_callback' => [$this, 'check_permission'], ]); // SMS test send (admin only) register_rest_route(self::API_NAMESPACE, '/sms/test', [ 'methods' => 'POST', 'callback' => [$this, 'test_sms_send'], 'permission_callback' => [$this, 'check_permission'], ]); // WeChat notification status register_rest_route(self::API_NAMESPACE, '/wechat/status', [ 'methods' => 'GET', 'callback' => [$this, 'get_wechat_status'], 'permission_callback' => [$this, 'check_permission'], ]); // WeChat settings update register_rest_route(self::API_NAMESPACE, '/wechat/settings', [ 'methods' => 'POST', 'callback' => [$this, 'update_wechat_settings'], 'permission_callback' => [$this, 'check_permission'], ]); // SMS auth: send verification code (public, rate-limited) register_rest_route(self::API_NAMESPACE, '/auth/send-sms-code', [ 'methods' => 'POST', 'callback' => [$this, 'auth_send_sms_code'], 'permission_callback' => '__return_true', ]); // SMS auth: register by phone (public) register_rest_route(self::API_NAMESPACE, '/auth/phone-register', [ 'methods' => 'POST', 'callback' => [$this, 'auth_phone_register'], 'permission_callback' => '__return_true', ]); // SMS auth: login by phone + password (public) register_rest_route(self::API_NAMESPACE, '/auth/phone-login', [ 'methods' => 'POST', 'callback' => [$this, 'auth_phone_login'], 'permission_callback' => '__return_true', ]); // SMS auth: login by phone + SMS code (public) register_rest_route(self::API_NAMESPACE, '/auth/phone-code-login', [ 'methods' => 'POST', 'callback' => [$this, 'auth_phone_code_login'], 'permission_callback' => '__return_true', ]); // SMS auth: bind phone to current user (logged-in) register_rest_route(self::API_NAMESPACE, '/auth/bind-phone', [ 'methods' => 'POST', 'callback' => [$this, 'auth_bind_phone'], 'permission_callback' => function () { return is_user_logged_in(); }, ]); // ── User Restrictions / Ban ── // List restrictions for a user (admin) register_rest_route(self::API_NAMESPACE, '/users/(?P\d+)/restrictions', [ 'methods' => 'GET', 'callback' => [$this, 'get_user_restrictions'], 'permission_callback' => [$this, 'check_permission'], ]); // Add restriction (admin) register_rest_route(self::API_NAMESPACE, '/users/(?P\d+)/restrict', [ 'methods' => 'POST', 'callback' => [$this, 'add_user_restriction'], 'permission_callback' => [$this, 'check_permission'], ]); // Remove restriction (admin) register_rest_route(self::API_NAMESPACE, '/users/restrictions/(?P\d+)', [ 'methods' => 'DELETE', 'callback' => [$this, 'remove_user_restriction'], 'permission_callback' => [$this, 'check_permission'], ]); // Restriction stats (admin) register_rest_route(self::API_NAMESPACE, '/users/restrictions/stats', [ 'methods' => 'GET', 'callback' => [$this, 'get_restriction_stats'], 'permission_callback' => [$this, 'check_permission'], ]); } /** * GET/POST /settings/mail-templates — 邮件内容模板 */ public function handle_mail_templates(\WP_REST_Request $request): \WP_REST_Response { $option_key = 'aksrt_mail_templates'; $fields = [ 'welcome_subject', 'welcome_body', 'comment_notify_subject', 'comment_notify_body', 'comment_reply_subject', 'comment_reply_body', 'password_reset_subject', 'password_reset_body', 'email_verify_subject', 'email_verify_body', ]; if ($request->get_method() === 'GET') { $stored = get_option($option_key, []); if (!is_array($stored)) $stored = []; $result = []; foreach ($fields as $f) { $result[$f] = sanitize_text_field((string) ($stored[$f] ?? '')); } return $this->success(['data' => $result]); } // POST $params = $this->get_json_params($request); $clean = []; foreach ($fields as $f) { $clean[$f] = wp_kses_post((string) ($params[$f] ?? '')); } update_option($option_key, $clean); return $this->success(['message' => __('邮件模板已保存', 'aksrt')]); } public function rest_handle_credit_settings(\WP_REST_Request $request): \WP_REST_Response { if ($request->get_method() === 'GET') { $config = \AKSRT\Settings\CreditsRuntime::get_credit_settings(); return $this->success(['data' => $config]); } $params = $this->get_json_params($request); $current = get_option('aksrt_credit_settings', []); if (!is_array($current)) { $current = []; } $merged = array_replace_recursive($current, $params); update_option('aksrt_credit_settings', $merged); return $this->success(['message' => __('积分配置已保存', 'aksrt')]); } public function rest_handle_auth_settings(\WP_REST_Request $request): \WP_REST_Response { $provider = SchemaProvider::get_instance(); $allowed = $provider->get_allowed_fields('users', 'auth'); if ($request->get_method() === 'GET') { $data = \AKSRT\Settings\Settings::get_all(); $invite = class_exists('\AKSRT\Settings\CreditsRuntime') ? \AKSRT\Settings\CreditsRuntime::get_invite_registration_config() : []; return $this->success(['data' => [ 'registration_email_verification_enabled' => \AKSRT\Settings\Settings::registration_requires_email_verification(), 'registration_email_verification_method' => \AKSRT\Settings\Settings::registration_verification_method(), 'invite_registration_enabled' => $invite['enabled'] ?? true, 'invite_code_length' => class_exists('\AKSRT\Settings\Settings') ? \AKSRT\Settings\Settings::invite_code_length() : 6, 'invite_register_field' => $invite['register_field'] ?? 'optional', 'invite_reject_invalid' => $invite['reject_invalid'] ?? false, ] + array_intersect_key($data, $allowed)]); } $params = $this->get_json_params($request); $settings = \AKSRT\Settings\Settings::get_all(); $sanitized = $this->sanitize_fields($params, $allowed); $settings = array_merge($settings, $sanitized); if (array_key_exists('invite_registration_enabled', $params)) { $settings['invite_registration_enabled'] = !empty($params['invite_registration_enabled']); } if (array_key_exists('invite_code_length', $params)) { $settings['invite_code_length'] = max(4, min(12, (int) $params['invite_code_length'])); } if (array_key_exists('invite_register_field', $params)) { $field = (string) $params['invite_register_field']; $settings['invit_code_mode'] = $field === 'required' ? 'must' : ($field === 'hidden' ? 'close' : 'open'); } if (array_key_exists('invite_reject_invalid', $params)) { $reward = is_array($settings['invite_reward'] ?? null) ? $settings['invite_reward'] : []; $reward['reject_invalid'] = !empty($params['invite_reject_invalid']); $settings['invite_reward'] = $reward; } if (array_key_exists('registration_email_verification_enabled', $params)) { $settings['registration_email_verification_enabled'] = !empty($params['registration_email_verification_enabled']); } if (array_key_exists('registration_email_verification_method', $params)) { $method = (string) $params['registration_email_verification_method']; $settings['registration_email_verification_method'] = in_array($method, ['link', 'code'], true) ? $method : 'link'; } update_option('aksrt_settings', $settings); \AKSRT\Settings\Settings::flush_settings_cache(); return $this->success(['message' => __('注册登录配置已保存', 'aksrt')]); } public function rest_handle_notification_settings(\WP_REST_Request $request): \WP_REST_Response { $provider = SchemaProvider::get_instance(); $allowed = $provider->get_allowed_fields('users', 'notifications'); if ($request->get_method() === 'GET') { $data = \AKSRT\Settings\Settings::get_all(); return $this->success(['data' => array_intersect_key($data, $allowed)]); } $params = $this->get_json_params($request); $settings = \AKSRT\Settings\Settings::get_all(); $settings = array_merge($settings, $this->sanitize_fields($params, $allowed)); update_option('aksrt_settings', $settings); \AKSRT\Settings\Settings::flush_settings_cache(); return $this->success(['message' => __('消息通知配置已保存', 'aksrt')]); } public function rest_get_notification_overview(\WP_REST_Request $request): \WP_REST_Response { $page = max(1, (int) $request->get_param('page')); $per_page = min(100, max(1, (int) $request->get_param('per_page'))); $type = sanitize_key((string) $request->get_param('type')); $is_read = $request->get_param('is_read'); $items = []; $unread = 0; if (class_exists('\AKSRT\Messages\Message')) { $args = ['limit' => $per_page, 'offset' => ($page - 1) * $per_page]; if ($type !== '') { $args['type'] = $type; } $items = \AKSRT\Messages\Message::get_instance()->get_notifications(get_current_user_id(), $args); if ($is_read !== null && $is_read !== '') { $want_read = (string) $is_read === '1'; $items = array_values(array_filter($items, static function ($item) use ($want_read) { return !empty($item['is_read']) === $want_read; })); } $unread = \AKSRT\Messages\Message::get_instance()->get_unread_count(get_current_user_id()); } $total = count($items); $types = []; $today = 0; $system = 0; foreach ($items as $item) { $itemType = sanitize_key((string) ($item['type'] ?? 'system')); $types[$itemType] = ($types[$itemType] ?? 0) + 1; if ($itemType === 'system' || $itemType === 'notice') { $system++; } $created = (string) ($item['created_at'] ?? ''); if ($created !== '' && str_starts_with($created, gmdate('Y-m-d'))) { $today++; } } return $this->success(['data' => [ 'recent' => $items, 'types' => array_map(static fn($key, $count) => ['type' => $key, 'count' => $count], array_keys($types), array_values($types)), 'summary' => [ 'total' => $total, 'unread' => $unread, 'today' => $today, 'system' => $system, ], 'pagination' => [ 'page' => $page, 'per_page' => $per_page, 'total_items' => $total, 'total_pages' => 1, ], ]]); } public function rest_mark_notification_read(\WP_REST_Request $request): \WP_REST_Response { if (!class_exists('\AKSRT\Messages\Message')) { return $this->success(['message' => __('消息系统未启用', 'aksrt')]); } $params = $this->get_json_params($request); $msg = \AKSRT\Messages\Message::get_instance(); if (!empty($params['mark_all'])) { $msg->mark_all_read(get_current_user_id()); } else { $id = sanitize_text_field((string) ($params['id'] ?? '')); if ($id !== '') { $msg->mark_read(get_current_user_id(), $id); } } return $this->success(['message' => __('已更新消息状态', 'aksrt')]); } public function rest_delete_notification_item(\WP_REST_Request $request): \WP_REST_Response { $user_id = get_current_user_id(); if ($user_id <= 0) { return $this->error(__('请先登录', 'aksrt'), 401); } $params = $this->get_json_params($request); $id = sanitize_text_field((string) ($params['id'] ?? $request->get_param('id') ?? '')); if ($id === '') { return $this->error(__('参数错误', 'aksrt'), 400); } if (function_exists('aksrt_delete_user_notification')) { aksrt_delete_user_notification($user_id, $id); } elseif (class_exists('\AKSRT\Messages\Message')) { \AKSRT\Messages\Message::get_instance()->mark_read($user_id, $id); } return $this->success([ 'message' => __('消息已删除', 'aksrt'), 'unread' => function_exists('aksrt_get_user_unread_notification_count') ? aksrt_get_user_unread_notification_count($user_id) : 0, ]); } public function rest_run_notification_cleanup(\WP_REST_Request $request): \WP_REST_Response { return $this->success(['message' => __('消息清理任务已受理', 'aksrt')]); } public function rest_handle_oauth(\WP_REST_Request $request): \WP_REST_Response { $provider = SchemaProvider::get_instance(); $allowed = $provider->get_allowed_fields('users', 'oauth'); if ($request->get_method() === 'GET') { $data = \AKSRT\Settings\Settings::get_all(); return $this->success(['data' => array_intersect_key($data, $allowed)]); } $params = $this->get_json_params($request); $settings = \AKSRT\Settings\Settings::get_all(); $settings = array_merge($settings, $this->sanitize_fields($params, $allowed)); update_option('aksrt_settings', $settings); \AKSRT\Settings\Settings::flush_settings_cache(); return $this->success(['message' => __('第三方登录配置已保存', 'aksrt')]); } public function rest_handle_oauth_proxy(\WP_REST_Request $request): \WP_REST_Response { $keys = [ 'oauth_proxy_mode', 'oauth_proxy_secret', 'oauth_proxy_server_url', 'oauth_proxy_server_providers', 'oauth_proxy_client_providers', 'oauth_proxy_gzh_type', ]; if ($request->get_method() === 'GET') { $all = \AKSRT\Settings\Settings::get_all(); $data = []; foreach ($keys as $key) { $data[$key] = $all[$key] ?? null; } return $this->success(['data' => $data]); } $params = $this->get_json_params($request); $settings = \AKSRT\Settings\Settings::get_all(); foreach ($keys as $key) { if (!array_key_exists($key, $params)) { continue; } $settings[$key] = is_array($params[$key]) ? array_values(array_map('sanitize_key', (array) $params[$key])) : sanitize_text_field((string) $params[$key]); } update_option('aksrt_settings', $settings); \AKSRT\Settings\Settings::flush_settings_cache(); return $this->success(['message' => __('OAuth 代理配置已保存', 'aksrt')]); } public function rest_upload_comment_image(\WP_REST_Request $request): \WP_REST_Response { $user_id = get_current_user_id(); if ($user_id <= 0) { return $this->error(__('请先登录', 'aksrt'), 401); } if (!function_exists('aksrt_user_can') || !aksrt_user_can('upload_comment_image', $user_id)) { return $this->error(__('当前账号没有上传评论图片的权限', 'aksrt'), 403); } if (empty($_FILES['image']) && empty($_FILES['file'])) { return $this->error(__('请选择要上传的图片', 'aksrt'), 400); } require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; $file_key = !empty($_FILES['image']) ? 'image' : 'file'; $file = $_FILES[$file_key]; $upload_error = isset($file['error']) ? (int) $file['error'] : UPLOAD_ERR_NO_FILE; if ($upload_error !== UPLOAD_ERR_OK) { return $this->error(__('图片文件上传失败,请重新选择', 'aksrt'), 400); } $settings = class_exists('\\AKSRT\\Settings\\Settings') ? \AKSRT\Settings\Settings::get_all() : []; $max_size_mb = max(1, min(10, (int) ($settings['comment_image_max_size'] ?? 2))); $actual_size = !empty($file['tmp_name']) && is_readable($file['tmp_name']) ? (int) filesize($file['tmp_name']) : 0; if ($actual_size <= 0 || $actual_size > $max_size_mb * MB_IN_BYTES) { return $this->error(sprintf(__('图片大小必须在 1 字节至 %dMB 之间', 'aksrt'), $max_size_mb), 413); } $mimes = [ 'jpg|jpeg|jpe' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif', 'webp' => 'image/webp', ]; $checked = wp_check_filetype_and_ext($file['tmp_name'], $file['name'], $mimes); $image_size = wp_getimagesize($file['tmp_name']); if (empty($checked['type']) || empty($checked['ext']) || !wp_match_mime_types('image', $checked['type']) || !$image_size || ((int) $image_size[0] * (int) $image_size[1]) > 40000000) { return $this->error(__('仅支持有效的 JPG、PNG、GIF 或 WebP 图片', 'aksrt'), 415); } if (class_exists('\AKSRT\Extensions\ContentAudit')) { $audit = \AKSRT\Extensions\ContentAudit::get_instance()->audit_image((string) $file['tmp_name']); if (empty($audit['passed'])) { return $this->error(__('图片未通过内容审核', 'aksrt'), 422); } } $attachment_id = media_handle_upload($file_key, 0, [], [ 'test_form' => false, 'mimes' => $mimes, ]); if (is_wp_error($attachment_id)) { return $this->error($attachment_id->get_error_message(), 400); } wp_update_post(['ID' => (int) $attachment_id, 'post_author' => $user_id]); if (!wp_attachment_is_image((int) $attachment_id)) { wp_delete_attachment((int) $attachment_id, true); return $this->error(__('上传文件不是有效图片', 'aksrt'), 415); } $url = wp_get_attachment_url((int) $attachment_id); if (!$url) { return $this->error(__('上传失败', 'aksrt'), 500); } return $this->success([ 'message' => __('图片上传成功', 'aksrt'), 'data' => [ 'url' => $url, 'attachment_id' => (int) $attachment_id, ], ]); } public function rest_get_credits_me(\WP_REST_Request $request): \WP_REST_Response { $user_id = get_current_user_id(); return $this->success(['data' => [ 'user_id' => $user_id, 'balance' => class_exists('\AKSRT\Credits\Credits') ? \AKSRT\Credits\Credits::balance($user_id) : 0, ]]); } public function rest_list_credit_users(\WP_REST_Request $request): \WP_REST_Response { $args = [ 'search' => (string) $request->get_param('search'), 'page' => (int) $request->get_param('page'), 'per_page' => (int) $request->get_param('per_page'), ]; $data = class_exists('\AKSRT\Credits\Credits') ? \AKSRT\Credits\Credits::list_users($args) : ['items' => [], 'total' => 0, 'page' => 1, 'per_page' => 20]; return $this->success(['data' => $data]); } public function rest_adjust_user_credits(\WP_REST_Request $request): \WP_REST_Response { if (!class_exists('\AKSRT\Credits\Credits')) { return $this->error(__('积分系统不可用', 'aksrt'), 500); } $user_id = (int) $request->get_param('id'); $params = $this->get_json_params($request); $delta = (int) ($params['delta'] ?? 0); $reason = sanitize_text_field((string) ($params['reason'] ?? 'admin')); if ($user_id <= 0 || $delta === 0) { return $this->error(__('用户或积分变动值无效', 'aksrt'), 422); } if ($delta > 0) { $result = \AKSRT\Credits\Credits::add($user_id, $delta, $reason, ['type' => 'user', 'id' => $user_id], 'Admin adjustment'); } else { $result = \AKSRT\Credits\Credits::deduct($user_id, abs($delta), $reason, ['type' => 'user', 'id' => $user_id], 'Admin adjustment'); } if (is_wp_error($result)) { return $this->error($result->get_error_message(), 422); } return $this->success(['data' => [ 'user_id' => $user_id, 'balance' => (int) $result, ], 'message' => __('积分调整已保存', 'aksrt')]); } public function rest_get_credits_log(\WP_REST_Request $request): \WP_REST_Response { $args = [ 'user_id' => (int) $request->get_param('user_id'), 'reason' => (string) $request->get_param('reason'), 'page' => (int) $request->get_param('page'), 'per_page' => (int) $request->get_param('per_page'), 'date_from' => (string) $request->get_param('date_from'), 'date_to' => (string) $request->get_param('date_to'), ]; $data = class_exists('\AKSRT\Credits\Credits') ? \AKSRT\Credits\Credits::get_log($args) : ['items' => [], 'total' => 0, 'page' => 1, 'per_page' => 20]; return $this->success(['data' => $data]); } }