用户功能设置收口与废弃后台链路清理

This commit is contained in:
2026-08-23 22:09:12 +08:00
parent 081eb0870d
commit 86692ff3f9
59 changed files with 506 additions and 1767 deletions
-2
View File
@@ -17,8 +17,6 @@ class SchemaTools {
'import-export' => SchemaToolsImportExport::build(),
'health' => SchemaToolsHealth::build(),
'backup' => SchemaToolsBackup::build(),
'email-rollback' => SchemaToolsEmailRollback::build(),
'frontend-modal-rollout' => SchemaToolsFrontendModalRollout::build(),
],
];
}
@@ -1,32 +0,0 @@
<?php
/**
* @package AKSRT
*/
namespace AKSRT\Admin\Schema;
defined('ABSPATH') || exit;
class SchemaToolsEmailRollback {
public static function build(): array {
return [
'key' => 'email-rollback',
'title' => '邮件回滚',
'version' => '1.0.0',
'option_key' => 'aksrt_settings',
'groups' => [
['key' => 'rollback', 'title' => '邮件回滚', 'fields' => [
['key' => 'rollback_type', 'label' => '回滚类型', 'type' => 'select', 'options' => [
['label' => '按时间范围', 'value' => 'date_range'],
['label' => '按邮件类型', 'value' => 'email_type'],
['label' => '全部回滚', 'value' => 'all'],
]],
['key' => 'rollback_date_from', 'label' => '开始日期', 'type' => 'date'],
['key' => 'rollback_date_to', 'label' => '结束日期', 'type' => 'date'],
['key' => 'rollback_execute', 'label' => '执行回滚', 'type' => 'button', 'danger' => true, 'help' => '此操作不可逆'],
]],
],
];
}
}
@@ -1,49 +0,0 @@
<?php
/**
* @package AKSRT
*/
namespace AKSRT\Admin\Schema;
defined('ABSPATH') || exit;
class SchemaToolsFrontendModalRollout {
public static function build(): array {
return [
'key' => 'frontend-modal-rollout',
'title' => '前台弹窗灰度',
'version' => '1.0.0',
'option_key' => 'aksrt_settings',
'groups' => [
[
'key' => 'rollout',
'title' => '弹窗新流程开关',
'fields' => [
[
'key' => 'frontend_modal_rollout_identity',
'label' => '官方认证新流程',
'type' => 'switch',
'default' => true,
'help' => '启用统一弹窗运行时与认证快照流程。',
],
[
'key' => 'frontend_modal_rollout_order',
'label' => '订单新流程',
'type' => 'switch',
'default' => true,
'help' => '启用订单详情快速开壳与状态同步流程。',
],
[
'key' => 'frontend_modal_rollout_vip',
'label' => '会员支付新流程',
'type' => 'switch',
'default' => true,
'help' => '启用统一会员购买、支付和结果同步流程。',
],
],
],
],
];
}
}
+16 -85
View File
@@ -475,26 +475,6 @@ class SchemaUsers {
]],
],
],
'signin' => [
'key' => 'signin',
'title' => '签到奖励',
'version' => '1.0.0',
'option_key' => 'aksrt_settings',
'groups' => [
['key' => 'rules', 'title' => '签到规则', 'fields' => [
['key' => 'signin_enabled', 'label' => '启用签到', 'type' => 'switch', 'default' => true],
['key' => 'signin_reward', 'label' => '每日签到奖励', 'type' => 'number', 'default' => 1, 'min' => 0, 'max' => 100],
['key' => 'signin_consecutive_bonus', 'label' => '连续签到加成', 'type' => 'switch', 'default' => true],
['key' => 'signin_consecutive_days', 'label' => '加成周期', 'type' => 'number', 'default' => 7, 'min' => 2, 'max' => 30],
['key' => 'signin_bonus_reward', 'label' => '周期奖励', 'type' => 'number', 'default' => 5, 'min' => 1, 'max' => 100],
]],
['key' => 'display', 'title' => '签到展示', 'fields' => [
['key' => 'signin_header_user_show', 'label' => '导航栏显示签到', 'type' => 'switch', 'default' => true],
['key' => 'signin_modal_auto_s', 'label' => '自动弹出签到', 'type' => 'switch', 'default' => false],
['key' => 'signin_modal_auto_expires', 'label' => '弹出间隔(天)', 'type' => 'number', 'default' => 1, 'min' => 1, 'max' => 30],
]],
],
],
'credits' => [
'key' => 'credits',
'title' => '积分设置',
@@ -551,72 +531,23 @@ class SchemaUsers {
'version' => '1.0.0',
'option_key' => 'aksrt_settings',
'groups' => [
['key' => 'center', 'title' => '用户中心', 'fields' => [
['key' => 'user_center_tabs', 'label' => '用户中心 Tab', 'type' => 'input', 'default' => 'profile,level,comments,favorites,vip,credits,revenue,auth', 'help' => '逗号分隔。level=我的等级;creator=创作中心;revenue=推广收益中心;auth=官方认证;等级、VIP、订单、创作中心、收益中心和认证会按功能开关自动注入'],
['key' => 'user_desc_std', 'label' => '默认签名', 'type' => 'input', 'default' => '这家伙很懒…', 'desc' => '用户未设置个人简介时显示的默认文案'],
['key' => 'user_city_s', 'label' => '显示城市(IP 归属地)', 'type' => 'switch', 'default' => true],
['key' => 'user_city_type', 'label' => '位置精度', 'type' => 'radio', 'default' => 'province', 'options' => [
['label' => '省份', 'value' => 'province'],
['label' => '省份+城市', 'value' => 'province_city'],
['label' => '国家+省份', 'value' => 'country_province'],
]],
['key' => 'user_join_day_my_name', 'label' => '站名', 'type' => 'input', 'default' => '本站', 'desc' => '用于「已加入 X 天」显示中的站点名称'],
['key' => 'user_cover_img', 'label' => '默认封面', 'type' => 'media', 'default' => ''],
['key' => 'user_rewrite_slug', 'label' => '用户页slug', 'type' => 'input', 'default' => 'user'],
['key' => 'user_follow_s', 'label' => '启用关注功能', 'type' => 'switch', 'default' => true],
['key' => 'user_online_s', 'label' => '显示在线状态', 'type' => 'switch', 'default' => true],
['key' => 'user_last_active_s', 'label' => '显示最后活跃', 'type' => 'switch', 'default' => true],
['key' => 'profile-media', 'title' => '用户资料', 'fields' => [
['key' => 'avatar_upload_s', 'label' => '允许用户上传头像', 'type' => 'switch', 'default' => true],
['key' => 'avatar_external', 'label' => '外部头像源', 'type' => 'radio', 'default' => '', 'options' => [
['label' => '关闭', 'value' => ''],
['label' => 'Gravatar', 'value' => 'gravatar'],
['label' => 'WeAvatar', 'value' => 'weavatar'],
['label' => 'Cravatar', 'value' => 'cravatar'],
['label' => '极客族 Gravatar 服务', 'value' => 'geekzu'],
['label' => 'loli Gravatar 服务', 'value' => 'loli'],
['label' => 'sep.cc Gravatar 服务', 'value' => 'sep'],
['label' => 'v2ex Gravatar 服务', 'value' => 'v2ex'],
], 'help' => '启用后,用户没有自定义头像时按邮箱获取外部头像。'],
['key' => 'avatar_default_img', 'label' => '用户默认头像', 'type' => 'media', 'default' => get_theme_file_uri('assets/img/avatar-default.png'), 'help' => '建议尺寸 100×100。'],
['key' => 'user_cover_upload_s', 'label' => '允许用户上传封面', 'type' => 'switch', 'default' => true],
['key' => 'user_cover_img', 'label' => '用户默认封面', 'type' => 'media', 'default' => get_theme_file_uri('assets/img/user_t.jpg'), 'help' => '建议尺寸 1000×400;用户未设置封面时显示此图。'],
['key' => 'user_desc_std', 'label' => '用户默认签名', 'type' => 'input', 'default' => '这家伙很懒,什么都没有写...', 'help' => '用户未设置个人简介时显示的默认文案。'],
]],
['key' => 'profile', 'title' => '资料页字段', 'fields' => [
['key' => 'user_profile_nickname', 'label' => '昵称', 'type' => 'switch', 'default' => true],
['key' => 'user_profile_email', 'label' => '邮箱', 'type' => 'switch', 'default' => true],
['key' => 'user_profile_url', 'label' => '个人主页', 'type' => 'switch', 'default' => true],
['key' => 'user_profile_desc', 'label' => '个人简介', 'type' => 'switch', 'default' => true],
['key' => 'user_profile_avatar', 'label' => '头像', 'type' => 'switch', 'default' => true],
['key' => 'user_profile_cover', 'label' => '封面图', 'type' => 'switch', 'default' => true],
['key' => 'user_profile_qq', 'label' => 'QQ', 'type' => 'switch', 'default' => false],
['key' => 'user_profile_wechat', 'label' => '微信', 'type' => 'switch', 'default' => false],
['key' => 'user_profile_weibo', 'label' => '微博', 'type' => 'switch', 'default' => false],
['key' => 'user_profile_github', 'label' => 'GitHub', 'type' => 'switch', 'default' => false],
['key' => 'user_profile_bilibili', 'label' => 'B站', 'type' => 'switch', 'default' => false],
['key' => 'user_profile_twitter', 'label' => 'Twitter', 'type' => 'switch', 'default' => false],
['key' => 'user_profile_linkedin', 'label' => 'LinkedIn', 'type' => 'switch', 'default' => false],
['key' => 'user_profile_facebook', 'label' => 'Facebook', 'type' => 'switch', 'default' => false],
['key' => 'user_profile_telegram', 'label' => 'Telegram', 'type' => 'switch', 'default' => false],
['key' => 'user_profile_douyin', 'label' => '抖音', 'type' => 'switch', 'default' => false],
['key' => 'user_profile_zhihu', 'label' => '知乎', 'type' => 'switch', 'default' => false],
]],
['key' => 'card', 'title' => '用户卡片', 'fields' => [
['key' => 'user_card_avatar', 'label' => '显示头像', 'type' => 'switch', 'default' => true],
['key' => 'user_card_name', 'label' => '显示用户名', 'type' => 'switch', 'default' => true],
['key' => 'user_card_desc', 'label' => '显示简介', 'type' => 'switch', 'default' => true],
['key' => 'user_card_count', 'label' => '显示统计', 'type' => 'switch', 'default' => true],
['key' => 'user_card_follow', 'label' => '显示关注按钮', 'type' => 'switch', 'default' => true],
['key' => 'user_card_position', 'label' => '卡片位置', 'type' => 'radio', 'default' => 'right', 'options' => [
['label' => '右侧', 'value' => 'right'],
['label' => '左侧', 'value' => 'left'],
['label' => '顶部', 'value' => 'top'],
]],
['key' => 'user_card_style', 'label' => '卡片样式', 'type' => 'radio', 'default' => 'default', 'options' => [
['label' => '默认', 'value' => 'default'],
['label' => '简洁', 'value' => 'simple'],
['label' => '详细', 'value' => 'detail'],
]],
['key' => 'user_card_bg', 'label' => '卡片背景', 'type' => 'media', 'default' => ''],
['key' => 'user_card_avatar_size', 'label' => '头像大小', 'type' => 'number', 'default' => 80, 'min' => 40, 'max' => 200],
]],
['key' => 'privacy', 'title' => '隐私设置', 'fields' => [
['key' => 'user_privacy_posts', 'label' => '隐藏文章', 'type' => 'switch', 'default' => false],
['key' => 'user_privacy_comments', 'label' => '隐藏评论', 'type' => 'switch', 'default' => false],
['key' => 'user_privacy_favorites', 'label' => '隐藏收藏', 'type' => 'switch', 'default' => false],
['key' => 'user_privacy_credits', 'label' => '隐藏积分', 'type' => 'switch', 'default' => false],
['key' => 'user_privacy_badge', 'label' => '隐藏徽章', 'type' => 'switch', 'default' => false],
['key' => 'user_privacy_online', 'label' => '隐藏在线状态', 'type' => 'switch', 'default' => false],
['key' => 'user_privacy_last_active', 'label' => '隐藏最后活跃', 'type' => 'switch', 'default' => false],
['key' => 'user_privacy_ip', 'label' => '隐藏IP归属地', 'type' => 'switch', 'default' => false],
['key' => 'user_privacy_location', 'label' => '隐藏位置', 'type' => 'switch', 'default' => false],
]],
],
],
'verify' => [
-135
View File
@@ -17,34 +17,6 @@ class ToolsController extends ControllerBase {
}
public function register_routes(): void {
// Email rollback: list users with recent email changes
register_rest_route(self::API_NAMESPACE, '/email-rollback/users', [
'methods' => 'GET',
'callback' => [$this, 'rest_email_rollback_list'],
'permission_callback' => [$this, 'check_permission'],
]);
// Email rollback: execute rollback
register_rest_route(self::API_NAMESPACE, '/email-rollback/users/(?P<id>\d+)/rollback', [
'methods' => 'POST',
'callback' => [$this, 'rest_email_rollback_execute'],
'permission_callback' => [$this, 'check_permission'],
]);
// Tools: system health (compact format for ExtensionTools.vue)
register_rest_route(self::API_NAMESPACE, '/tools/health', [
'methods' => 'GET',
'callback' => [$this, 'get_tools_health'],
'permission_callback' => [$this, 'check_permission'],
]);
// Tools: maintenance actions
register_rest_route(self::API_NAMESPACE, '/tools/maintenance', [
'methods' => 'POST',
'callback' => [$this, 'run_maintenance'],
'permission_callback' => [$this, 'check_permission'],
]);
// Tools: update center
register_rest_route(self::API_NAMESPACE, '/tools/update-info', [
'methods' => 'GET',
@@ -65,85 +37,6 @@ class ToolsController extends ControllerBase {
]);
}
/**
* GET /tools/health — compact health data for the tools page.
*/
public function get_tools_health(): \WP_REST_Response {
global $wpdb;
$upload_dir = wp_upload_dir();
$upload_ok = !empty($upload_dir['error']) === false && is_dir($upload_dir['basedir']);
$db_ok = true;
$db_status = '正常';
$expected_tables = [
$wpdb->prefix . 'aksrt_credit_log',
$wpdb->prefix . 'aksrt_signin_log',
$wpdb->prefix . 'aksrt_dl_token',
$wpdb->prefix . 'aksrt_notification',
];
$missing = [];
foreach ($expected_tables as $table) {
if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table)) !== $table) {
$missing[] = str_replace($wpdb->prefix, '', $table);
}
}
if (!empty($missing)) {
$db_ok = false;
$db_status = '缺少: ' . implode(', ', $missing);
}
return $this->success([
'data' => [
'php_version' => PHP_VERSION,
'wp_version' => get_bloginfo('version'),
'db_status' => $db_status,
'db_ok' => $db_ok,
'upload_dir' => $upload_dir['basedir'],
'upload_ok' => $upload_ok,
'theme_version' => wp_get_theme()->get('Version') ?? 'unknown',
],
]);
}
/**
* POST /tools/maintenance — run a maintenance action.
*/
public function run_maintenance(\WP_REST_Request $request): \WP_REST_Response {
$params = $this->get_json_params($request);
$action = sanitize_key((string) ($params['action'] ?? ''));
switch ($action) {
case 'flush_cache':
// Flush WordPress object cache
wp_cache_flush();
// Clear transients
global $wpdb;
$wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_aksrt_%' OR option_name LIKE '_transient_timeout_aksrt_%'");
return $this->success(['message' => __('缓存已清除', 'aksrt')]);
case 'optimize_db':
global $wpdb;
$tables = [
$wpdb->prefix . 'aksrt_credit_log',
$wpdb->prefix . 'aksrt_signin_log',
$wpdb->prefix . 'aksrt_dl_token',
$wpdb->prefix . 'aksrt_notification',
];
$optimized = 0;
foreach ($tables as $table) {
if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table)) === $table) {
$wpdb->query("OPTIMIZE TABLE {$table}");
$optimized++;
}
}
return $this->success(['message' => sprintf(__('已优化 %d 个数据表', 'aksrt'), $optimized)]);
default:
return $this->error('未知的维护操作: ' . esc_html($action));
}
}
public function get_update_info(): \WP_REST_Response {
$theme = wp_get_theme();
$info = [
@@ -199,32 +92,4 @@ class ToolsController extends ControllerBase {
]);
}
public function rest_email_rollback_list(\WP_REST_Request $request): \WP_REST_Response {
if (!class_exists('\AKSRT\Auth\EmailRollback')) {
return $this->success(['data' => ['items' => [], 'total' => 0, 'page' => 1, 'per_page' => 20]]);
}
$page = max(1, (int) $request->get_param('page'));
$per_page = min(100, max(1, (int) $request->get_param('per_page')));
$data = \AKSRT\Auth\EmailRollback::list_pending($page, $per_page);
return $this->success(['data' => $data]);
}
public function rest_email_rollback_execute(\WP_REST_Request $request): \WP_REST_Response {
if (!class_exists('\AKSRT\Auth\EmailRollback')) {
return $this->error(__('邮箱回滚功能不可用', 'aksrt'), 500);
}
$user_id = (int) $request->get_param('id');
$result = \AKSRT\Auth\EmailRollback::rollback($user_id, get_current_user_id());
if (empty($result['success'])) {
return $this->error((string) ($result['error'] ?? __('邮箱回滚失败', 'aksrt')), 422);
}
return $this->success([
'message' => (string) ($result['message'] ?? __('邮箱已回滚', 'aksrt')),
'data' => $result,
]);
}
}
@@ -54,8 +54,10 @@ trait UserControllerProfileMediaOperations {
return $this->error(__('请先登录', 'aksrt'), 401);
}
$capability = $is_avatar ? 'upload_avatar' : 'upload_profile_background';
if (!function_exists('aksrt_user_can') || !aksrt_user_can($capability, $user_id)) {
$upload_enabled = $is_avatar
? function_exists('aksrt_is_avatar_upload_enabled') && aksrt_is_avatar_upload_enabled()
: function_exists('aksrt_is_user_cover_upload_enabled') && aksrt_is_user_cover_upload_enabled();
if (!$upload_enabled) {
return $this->error($is_avatar
? __('当前账号没有上传头像的权限', 'aksrt')
: __('当前账号没有上传用户资料卡背景图的权限', 'aksrt'), 403);