feat(messages): redesign native message admin page
- Rebuild users.php?page=aksrt_messages: overview stats, collapsible compose card (users list / role recipients), read-state views, type/recipient/keyword filters, bulk mark-read/delete, shared AdminListPagination - Extract NotificationAdminQuery / AdminBroadcast / MessageTypes under src/Messages; page logic lives in UsersMenusMessages trait - Page-scoped assets/css/admin/messages.css - Remove dead aksrt_notification_type_label() and Message::get_all_notifications() Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bbb41547e2
commit
6681b0c306
9 files changed
+1081
-110
No files matched your search
@@ -0,0 +1,55 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* 消息管理后台(users.php → aksrt_messages)契约:
|
||||
* 1) 页面由独立 trait 承载,UsersMenus 只做组合与路由注册;
|
||||
* 2) 写操作走 admin_post + nonce + 能力校验;
|
||||
* 3) SQL 全部在 NotificationAdminQuery 内且经 prepare;
|
||||
* 4) 分页用共享 AdminListPagination;
|
||||
* 5) 旧实现与死代码已删除。
|
||||
*/
|
||||
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const test = require('node:test');
|
||||
|
||||
const root = path.resolve(__dirname, '../..');
|
||||
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
|
||||
|
||||
test('messages page is composed from its own trait', () => {
|
||||
const menus = read('src/Admin/Native/UsersMenus.php');
|
||||
assert.ok(menus.includes('use UsersMenusMessages;'));
|
||||
assert.ok(menus.includes("'aksrt_messages'"));
|
||||
assert.ok(menus.includes("add_action('admin_post_aksrt_users_send_message', [$this, 'handle_send_message'])"));
|
||||
assert.ok(menus.includes("add_action('admin_post_aksrt_users_bulk_messages', [$this, 'handle_bulk_messages'])"));
|
||||
assert.ok(menus.includes("add_action('admin_enqueue_scripts', [$this, 'enqueue_message_assets'])"));
|
||||
// 旧实现不得残留在壳类中。
|
||||
assert.doesNotMatch(menus, /function render_messages_page|function handle_send_message|message_sent|message_failed/);
|
||||
assert.doesNotMatch(menus, /aksrt_notification/);
|
||||
});
|
||||
|
||||
test('write handlers check capability and nonce', () => {
|
||||
const page = read('src/Admin/Native/UsersMenusMessages.php');
|
||||
assert.match(page, /function handle_send_message\(\): void \{\s*\$this->ensure_cap\(\);\s*check_admin_referer\('aksrt_users_send_message'\);/);
|
||||
assert.match(page, /function handle_bulk_messages\(\): void \{\s*\$this->ensure_cap\(\);\s*check_admin_referer\('aksrt_users_bulk_messages'\);/);
|
||||
assert.ok(page.includes("wp_nonce_field('aksrt_users_send_message')"));
|
||||
assert.ok(page.includes("wp_nonce_field('aksrt_users_bulk_messages')"));
|
||||
// 页面层不直接碰数据库,分页走共享组件。
|
||||
assert.doesNotMatch(page, /\$wpdb/);
|
||||
assert.ok(page.includes('AdminListPagination::render('));
|
||||
});
|
||||
|
||||
test('admin query keeps SQL prepared and bulk size capped', () => {
|
||||
const query = read('src/Messages/NotificationAdminQuery.php');
|
||||
assert.match(query, /DELETE FROM \{\$table\} WHERE id IN \(\{\$in\}\)", \$ids\)/);
|
||||
assert.ok(query.includes("array_fill(0, count($ids), '%d')"));
|
||||
assert.ok(query.includes('array_slice($ids, 0, self::MAX_BULK)'));
|
||||
assert.ok(query.includes('$wpdb->esc_like($s)'));
|
||||
});
|
||||
|
||||
test('dead notification helpers are removed', () => {
|
||||
assert.doesNotMatch(read('inc/modules/user-notifications.php'), /aksrt_notification_type_label/);
|
||||
assert.doesNotMatch(read('src/Messages/Message.php'), /get_all_notifications/);
|
||||
assert.ok(fs.existsSync(path.join(root, 'assets/css/admin/messages.css')));
|
||||
});
|
||||
Reference in new issue
Block a user