From 194280af72dce57dbac2b0af769e94baca17e24e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 6 Oct 2026 14:35:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(admin):=20=E7=A7=BB=E9=99=A4=E6=94=AF?= =?UTF-8?q?=E4=BB=98=E4=B8=AD=E5=BF=83=E7=9A=84=E2=80=9C=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E2=80=9D=E5=AD=90=E8=8F=9C=E5=8D=95=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 下载不做记录,支付中心下的“下载记录”页面及相关链路整体删除。 删除的内容: - src/Admin/Native/PayDownloadLogs.php(页面渲染、批量删除、 令牌查询)整文件移除。 - PayMenus 中的 download_logs 子菜单注册(概览页快捷入口由同一 份 pages() 数组生成,随之消失)。 - functions.php 中的 PayDownloadLogs::init() 接线。 - 各入口跳转链接:付费文章列表的操作按钮、用户列表“积分分成” 列的操作链接、用户列表行操作。 - “保存用户下载记录(条) / 保存文章下载记录(条)”两个设置项及其 消费链:SchemaPayment.php、assets/admin 侧 knowledge.js 的字段 与默认值、PaymentRuntime.php 的 user_log / post_log。 - 前台下载中心登录提示里的“管理下载记录”文案(该处本就没有 可跳转的管理页面)。 未改动内容: - aksrt_dl_token 数据表仍由 DBMigrator 创建、uninstall.php 仍会 删除:存量站点可能留有历史令牌行,属数据而非功能,迁移风险 高于收益。 - 独立下载页面开关(down_alone_page)与远程文件转本地等下载 行为配置保留。 - 资源下载量(_aksrt_res_download_count)仍是只读口径:下载走 普通外链,主题内没有写入方,本次不新增下载统计。 download-direct-contract.test.cjs 中原有“下载记录页面展示历史 令牌”用例反向改写为三项断言:页面与接线已删除、记录数设置项 已注销、下载仍不做记录。 验证:node --test "tests/*/*.test.cjs" 517 项全部通过; php -l 全部改动文件无语法错误;重新构建 admin SPA,确认产物 中不含被移除的字段与菜单。 --- .../src/schema/sections/payment/knowledge.js | 4 - functions.php | 3 - src/Admin/Native/PayDownloadLogs.php | 284 ------------------ src/Admin/Native/PayMenus.php | 11 - src/Admin/Native/PayProducts.php | 4 - src/Admin/Schema/SchemaPayment.php | 2 - src/Settings/PaymentRuntime.php | 2 - src/User/CreditsAdmin.php | 6 - templates/pages/page-download.php | 2 +- .../download-direct-contract.test.cjs | 30 +- 10 files changed, 27 insertions(+), 321 deletions(-) delete mode 100644 src/Admin/Native/PayDownloadLogs.php diff --git a/assets/admin/src/schema/sections/payment/knowledge.js b/assets/admin/src/schema/sections/payment/knowledge.js index ef237e29..49071899 100644 --- a/assets/admin/src/schema/sections/payment/knowledge.js +++ b/assets/admin/src/schema/sections/payment/knowledge.js @@ -29,8 +29,6 @@ export const knowledgeSchema = { payment_order_status_closed: '已关闭', pay_service: [], down_alone_page: false, - down_user_log: 50, - down_post_log: 50, down_remote_to_local_s: true, down_remote_to_local_size: 2048, down_remote_to_local_ext: 'zip,rar,7z,text,png,jpg,jpeg,gif,mp3,mp4,avi,wmv,flv,swf,doc,docx,xls,xlsx,ppt,pptx,pdf', @@ -172,8 +170,6 @@ export const knowledgeSchema = { title: '付费下载', fields: [ { key: 'down_alone_page', label: '独立下载页面', type: 'switch', default: false, help: '开启后,付费资源的下载链接会跳转独立页面显示' }, - { key: 'down_user_log', label: '保存用户下载记录(条)', type: 'number', default: 50, min: 0, help: '填0则不保存,注意记录量太大可能会影响网站性能' }, - { key: 'down_post_log', label: '保存文章下载记录(条)', type: 'number', default: 50, min: 0, help: '填0则不保存,注意记录量太大可能会影响网站性能' }, { key: 'down_remote_to_local_s', label: '远程文件转本地文件下载', type: 'switch', default: true, help: '当下载地址为外链文件时,先将远程文件下载到本地服务器,再提供给用户下载,可完全隐藏远程下载地址' }, { key: 'down_remote_to_local_size', label: '文件大小限制(Kb)', type: 'number', default: 2048, min: 0 }, { key: 'down_remote_to_local_ext', label: '文件格式限制', type: 'input', default: 'zip,rar,7z,text,png,jpg,jpeg,gif,mp3,mp4,avi,wmv,flv,swf,doc,docx,xls,xlsx,ppt,pptx,pdf', help: '限制使用此功能的文件格式,多个用英文逗号隔开' }, diff --git a/functions.php b/functions.php index 5274b852..24df1dd4 100644 --- a/functions.php +++ b/functions.php @@ -406,9 +406,6 @@ if (is_admin() && class_exists('\AKSRT\Admin\Native\PayOrders')) { if (is_admin() && class_exists('\AKSRT\Admin\Native\PayProducts')) { \AKSRT\Admin\Native\PayProducts::get_instance()->init(); } -if (is_admin() && class_exists('\AKSRT\Admin\Native\PayDownloadLogs')) { - \AKSRT\Admin\Native\PayDownloadLogs::get_instance()->init(); -} if (is_admin() && class_exists('\AKSRT\Admin\Native\PayWithdrawals')) { \AKSRT\Admin\Native\PayWithdrawals::get_instance()->init(); } diff --git a/src/Admin/Native/PayDownloadLogs.php b/src/Admin/Native/PayDownloadLogs.php deleted file mode 100644 index 6330f365..00000000 --- a/src/Admin/Native/PayDownloadLogs.php +++ /dev/null @@ -1,284 +0,0 @@ -ensure_cap(); - - if ($this->is_bulk_delete_request()) { - $this->handle_bulk_delete(); - } - - echo '

' . esc_html__('下载记录', 'aksrt') . '

'; - - if (isset($_GET['dl_deleted'])) { - echo '

' . esc_html(sprintf( - /* translators: %d: deleted record count */ - __('已删除 %d 条下载记录。', 'aksrt'), - max(0, (int) $_GET['dl_deleted']) - )) . '

'; - } elseif (isset($_GET['dl_empty'])) { - echo '

' . esc_html__('未选择需要删除的记录。', 'aksrt') . '

'; - } - - if (!class_exists('\AKSRT\Core\DBMigrator')) { - echo '

' . esc_html__('数据库服务不可用。', 'aksrt') . '

'; - return; - } - - $table = \AKSRT\Core\DBMigrator::table('dl_token'); - if ($table === '') { - echo '

' . esc_html__('下载令牌表未初始化。', 'aksrt') . '

'; - return; - } - - $post_id = isset($_GET['post_id']) ? max(0, (int) $_GET['post_id']) : 0; - $user_id = isset($_GET['user_id']) ? max(0, (int) $_GET['user_id']) : 0; - $only_used = !isset($_GET['used']) || (string) $_GET['used'] !== '0'; - $page_num = max(1, (int) ($_GET['paged'] ?? 1)); - $per_page = 30; - - $result = $this->query_logs($table, [ - 'post_id' => $post_id, - 'user_id' => $user_id, - 'only_used' => $only_used, - 'limit' => $per_page, - 'offset' => ($page_num - 1) * $per_page, - ]); - $items = $result['items']; - $total = $result['total']; - $pages = max(1, (int) ceil($total / $per_page)); - - echo '

' . esc_html__('基于下载令牌表(aksrt_dl_token)。下载已改为直连模式,不再签发新令牌,以下为历史记录。', 'aksrt') . '

'; - - echo '
'; - echo ''; - echo ' '; - echo ' '; - echo ' '; - submit_button(__('筛选', 'aksrt'), 'secondary', '', false); - echo ' ' . esc_html__('重置', 'aksrt') . ''; - echo '
'; - - // 批量操作(多选 / 单选)包裹列表;删除成功后重定向回当前筛选视图。 - echo '
'; - wp_nonce_field(self::NONCE); - echo '
'; - echo ''; - echo ''; - echo ''; - echo '

'; - - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - - if (!$items) { - echo ''; - } - - $seq_offset = ($page_num - 1) * $per_page; - foreach ($items as $i => $row) { - $uid = (int) ($row['user_id'] ?? 0); - $pid = (int) ($row['post_id'] ?? 0); - $token = (string) ($row['token'] ?? ''); - $user = $uid > 0 ? get_userdata($uid) : null; - $title = $pid > 0 ? get_the_title($pid) : ''; - if ($title === '') { - $title = $pid > 0 ? sprintf(__('(已删除 #%d)', 'aksrt'), $pid) : '—'; - } - $edit = $pid > 0 ? get_edit_post_link($pid, 'raw') : ''; - - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - echo ''; - } - echo '
' . esc_html__('序号', 'aksrt') . '' . esc_html__('文章', 'aksrt') . '' . esc_html__('用户', 'aksrt') . '' . esc_html__('积分消耗', 'aksrt') . '' . esc_html__('IP', 'aksrt') . '' . esc_html__('时间', 'aksrt') . '
' . esc_html__('暂无下载记录。', 'aksrt') . '
' . esc_html((string) ($seq_offset + $i + 1)) . ''; - if ($edit) { - echo '' . esc_html($title) . ''; - } else { - echo esc_html($title); - } - if ($pid > 0) { - echo '
' . esc_html__('仅此文章', 'aksrt') . ''; - } - echo '
'; - if ($user) { - echo esc_html($user->display_name . ' (#' . $uid . ')'); - echo '
' . esc_html__('仅此用户', 'aksrt') . ''; - } else { - echo esc_html((string) $uid); - } - echo '
' . esc_html((string) (int) ($row['cost'] ?? 0)) . '' . esc_html((string) ($row['ip_bind'] ?? '')) . '' . esc_html((string) ($row['created_at'] ?? '')) . '
'; - echo '
'; - - if ($pages > 1) { - echo '
'; - echo paginate_links([ - 'base' => add_query_arg('paged', '%#%'), - 'format' => '', - 'prev_text' => '«', - 'next_text' => '»', - 'total' => $pages, - 'current' => $page_num, - ]); - echo '
'; - } - echo ''; - } - - /** - * 当前页面 URL(含筛选参数),用于批量表单回帖与删除后重定向。 - */ - private function current_url(): string { - $args = ['page' => self::PAGE_SLUG]; - foreach (['post_id', 'user_id', 'used', 'paged'] as $key) { - if (isset($_GET[$key])) { - $args[$key] = wp_unslash($_GET[$key]); - } - } - return add_query_arg($args, admin_url('admin.php')); - } - - private function is_bulk_delete_request(): bool { - return (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST') - && isset($_POST['bulk_action']) - && ((string) wp_unslash($_POST['bulk_action']) === 'delete'); - } - - /** - * 批量删除选中的下载令牌记录;完成后重定向回当前筛选视图,避免刷新重复提交。 - */ - private function handle_bulk_delete(): void { - check_admin_referer(self::NONCE); - - $raw = isset($_POST['dl_token']) ? (array) wp_unslash($_POST['dl_token']) : []; - $tokens = array_values(array_unique(array_filter($raw, static function ($token): bool { - return is_string($token) && preg_match('/^[A-Za-z0-9]{1,64}$/', $token) === 1; - }))); - $tokens = array_slice($tokens, 0, self::BULK_DELETE_LIMIT); - - if (!$tokens) { - wp_safe_redirect(add_query_arg('dl_empty', '1', $this->current_url())); - exit; - } - - $deleted = $this->delete_tokens($tokens); - wp_safe_redirect(add_query_arg('dl_deleted', $deleted, $this->current_url())); - exit; - } - - /** - * @param array $tokens - */ - private function delete_tokens(array $tokens): int { - global $wpdb; - - if (!class_exists('\AKSRT\Core\DBMigrator')) { - return 0; - } - $table = \AKSRT\Core\DBMigrator::table('dl_token'); - if ($table === '') { - return 0; - } - - $placeholders = implode(',', array_fill(0, count($tokens), '%s')); - $sql = "DELETE FROM {$table} WHERE token IN ({$placeholders})"; - - return (int) $wpdb->query($wpdb->prepare($sql, $tokens)); - } - - /** - * @param array{post_id?:int,user_id?:int,only_used?:bool,limit?:int,offset?:int} $args - * @return array{items: array>, total:int} - */ - private function query_logs(string $table, array $args): array { - global $wpdb; - - $where = ['1=1']; - $params = []; - - $post_id = (int) ($args['post_id'] ?? 0); - if ($post_id > 0) { - $where[] = 'post_id = %d'; - $params[] = $post_id; - } - $user_id = (int) ($args['user_id'] ?? 0); - if ($user_id > 0) { - $where[] = 'user_id = %d'; - $params[] = $user_id; - } - if (!empty($args['only_used'])) { - $where[] = 'used_count > 0'; - } - - $where_sql = implode(' AND ', $where); - $limit = max(1, min(100, (int) ($args['limit'] ?? 30))); - $offset = max(0, (int) ($args['offset'] ?? 0)); - - $count_sql = "SELECT COUNT(*) FROM {$table} WHERE {$where_sql}"; - $total = $params - ? (int) $wpdb->get_var($wpdb->prepare($count_sql, $params)) - : (int) $wpdb->get_var($count_sql); - - $sql = "SELECT * FROM {$table} WHERE {$where_sql} ORDER BY created_at DESC LIMIT %d OFFSET %d"; - $list_params = $params; - $list_params[] = $limit; - $list_params[] = $offset; - $rows = $wpdb->get_results($wpdb->prepare($sql, $list_params), ARRAY_A); - - return [ - 'items' => is_array($rows) ? $rows : [], - 'total' => $total, - ]; - } - - private function ensure_cap(): void { - if (!current_user_can(self::CAPABILITY)) { - wp_die(esc_html__('您没有权限访问此页面。', 'aksrt')); - } - } -} diff --git a/src/Admin/Native/PayMenus.php b/src/Admin/Native/PayMenus.php index 0df6a43c..03147255 100644 --- a/src/Admin/Native/PayMenus.php +++ b/src/Admin/Native/PayMenus.php @@ -63,17 +63,6 @@ class PayMenus { wp_die(esc_html__('付费文章模块未初始化。', 'aksrt')); }, ], - 'download_logs' => [ - 'slug' => 'aksrt_download_logs', - 'title' => __('下载记录', 'aksrt'), - 'callback' => static function (): void { - if (class_exists('AKSRT\\Admin\\Native\\PayDownloadLogs')) { - PayDownloadLogs::get_instance()->render_page(); - return; - } - wp_die(esc_html__('下载记录模块未初始化。', 'aksrt')); - }, - ], 'coupons' => [ 'slug' => 'aksrt_coupons', 'title' => __('优惠码', 'aksrt'), diff --git a/src/Admin/Native/PayProducts.php b/src/Admin/Native/PayProducts.php index 18dfef9f..460497db 100644 --- a/src/Admin/Native/PayProducts.php +++ b/src/Admin/Native/PayProducts.php @@ -138,10 +138,6 @@ class PayProducts { echo '' . esc_html__('编辑', 'aksrt') . ''; } echo '' . esc_html__('订单', 'aksrt') . ''; - if ($pt === \AKSRT\Core\DomainModel::PAY_TYPE_DOWNLOAD) { - $dl_url = $this->page_url('aksrt_download_logs', ['post_id' => $post_id]); - echo '' . esc_html__('下载记录', 'aksrt') . ''; - } $permalink = get_permalink($post_id); if ($permalink) { echo '' . esc_html__('查看', 'aksrt') . ''; diff --git a/src/Admin/Schema/SchemaPayment.php b/src/Admin/Schema/SchemaPayment.php index 68fd4412..24822e78 100644 --- a/src/Admin/Schema/SchemaPayment.php +++ b/src/Admin/Schema/SchemaPayment.php @@ -81,8 +81,6 @@ class SchemaPayment { ['key' => 'pay_type_option', 'label' => '商品功能配置', 'type' => 'tabbed', 'tabs' => [ ['key' => 'download', 'title' => '付费下载', 'fields' => [ ['key' => 'down_alone_page', 'label' => '独立下载页面', 'type' => 'switch', 'default' => false, 'help' => '开启后,付费资源的下载链接会跳转独立页面显示'], - ['key' => 'down_user_log', 'label' => '保存用户下载记录(条)', 'type' => 'number', 'default' => 50, 'min' => 0, 'help' => '填0则不保存,注意记录量太大可能会影响网站性能'], - ['key' => 'down_post_log', 'label' => '保存文章下载记录(条)', 'type' => 'number', 'default' => 50, 'min' => 0, 'help' => '填0则不保存,注意记录量太大可能会影响网站性能'], ['key' => 'down_remote_to_local_s', 'label' => '远程文件转本地文件下载', 'type' => 'switch', 'default' => true, 'help' => '当下载地址为外链文件时,先将远程文件下载到本地服务器,再提供给用户下载,可完全隐藏远程下载地址'], ['key' => 'down_remote_to_local_size', 'label' => '文件大小限制(Kb)', 'type' => 'number', 'default' => 2048, 'min' => 0], ['key' => 'down_remote_to_local_ext', 'label' => '文件格式限制', 'type' => 'input', 'default' => 'zip,rar,7z,text,png,jpg,jpeg,gif,mp3,mp4,avi,wmv,flv,swf,doc,docx,xls,xlsx,ppt,pptx,pdf', 'help' => '限制使用此功能的文件格式,多个用英文逗号隔开'], diff --git a/src/Settings/PaymentRuntime.php b/src/Settings/PaymentRuntime.php index 900f0c75..f4d52f24 100644 --- a/src/Settings/PaymentRuntime.php +++ b/src/Settings/PaymentRuntime.php @@ -48,8 +48,6 @@ class PaymentRuntime { 'enabled' => true, 'remote' => !isset($settings['down_remote_to_local_s']) || !empty($settings['down_remote_to_local_s']), 'verify_nonce' => !isset($settings['down_verify_nonce']) || !empty($settings['down_verify_nonce']), - 'user_log' => max(0, (int) ($settings['down_user_log'] ?? 50)), - 'post_log' => max(0, (int) ($settings['down_post_log'] ?? 50)), 'remote_size' => max(0, (int) ($settings['down_remote_to_local_size'] ?? 2048)), 'remote_ext' => sanitize_text_field((string) ($settings['down_remote_to_local_ext'] ?? 'zip,rar,7z')), 'alone_page' => !empty($settings['down_alone_page']), diff --git a/src/User/CreditsAdmin.php b/src/User/CreditsAdmin.php index 63a63231..1dc07a37 100644 --- a/src/User/CreditsAdmin.php +++ b/src/User/CreditsAdmin.php @@ -88,7 +88,6 @@ class CreditsAdmin { $bits[] = '' . esc_html__('分成明细', 'aksrt') . ''; } } - $bits[] = '' . esc_html__('下载记录', 'aksrt') . ''; $bits[] = '' . esc_html__('订单', 'aksrt') . ''; if (!$bits) { @@ -129,11 +128,6 @@ class CreditsAdmin { esc_html(sprintf(__('调整%s', 'aksrt'), $currency_name)) ); } - $actions['aksrt_user_dl_logs'] = sprintf( - '%s', - esc_url(admin_url('admin.php?page=aksrt_download_logs&user_id=' . (int) $user->ID)), - esc_html__('下载记录', 'aksrt') - ); return $actions; } diff --git a/templates/pages/page-download.php b/templates/pages/page-download.php index 193e0589..e8f94bcc 100644 --- a/templates/pages/page-download.php +++ b/templates/pages/page-download.php @@ -92,7 +92,7 @@ $dl_requires_login = function_exists('aksrt_user_can') && !aksrt_user_can('resou - + diff --git a/tests/widget-system/download-direct-contract.test.cjs b/tests/widget-system/download-direct-contract.test.cjs index 2728071d..00024063 100644 --- a/tests/widget-system/download-direct-contract.test.cjs +++ b/tests/widget-system/download-direct-contract.test.cjs @@ -114,8 +114,30 @@ test('cms-download.js only serves the cashier now', () => { assert.match(read('src/Core/ScriptsPart1b.php'), /'aksrt-cms-download'/); }); -test('the download logs page reports historical token records', () => { - const page = read('src/Admin/Native/PayDownloadLogs.php'); - assert.match(page, /aksrt_dl_token/); - assert.match(page, /不再签发新令牌/); +test('the admin download-logs page and its wiring are gone', () => { + // 下载记录菜单页面:类文件、菜单注册、init 接线、各入口链接全部移除。 + assert.equal(exists('src/Admin/Native/PayDownloadLogs.php'), false); + assert.doesNotMatch(read('src/Admin/Native/PayMenus.php'), /download_logs|aksrt_download_logs|PayDownloadLogs/) + assert.doesNotMatch(read('functions.php'), /PayDownloadLogs/) + assert.doesNotMatch(read('src/Admin/Native/PayProducts.php'), /aksrt_download_logs/) + assert.doesNotMatch(read('src/User/CreditsAdmin.php'), /aksrt_download_logs|下载记录/) +}) + +test('download log retention settings no longer exist', () => { + // 「保存用户下载记录/保存文章下载记录」两个设置项及其消费链一并注销。 + assert.doesNotMatch(read('src/Admin/Schema/SchemaPayment.php'), /down_user_log|down_post_log/) + assert.doesNotMatch(read('assets/admin/src/schema/sections/payment/knowledge.js'), /down_user_log|down_post_log/) + assert.doesNotMatch(read('src/Settings/PaymentRuntime.php'), /down_user_log|down_post_log|'user_log'|'post_log'/) +}) + +test('downloads stay unrecorded', () => { + // 下载不做记录:没有任何 PHP 写入下载计数或下载令牌。 + const php = [ + 'inc/helpers/aksrt-pay.php', + 'inc/helpers/aksrt-resource.php', + 'src/Content/PayRest.php', + 'src/Content/Visibility.php', + ].map(read).join('\n') + assert.doesNotMatch(php, /update_post_meta\([^)]*download_count/) + assert.doesNotMatch(php, /aksrt_update_post_counter\([^)]*download/) });